diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_inter.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/s_inter.c | 1000 |
1 files changed, 0 insertions, 1000 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_inter.c b/apps/plugins/pdbox/PDa/src/s_inter.c index 37c44770ed..9df9c82b40 100644 --- a/apps/plugins/pdbox/PDa/src/s_inter.c +++ b/apps/plugins/pdbox/PDa/src/s_inter.c | |||
@@ -998,1003 +998,3 @@ void glob_quit(void *dummy) | |||
998 | sys_bail(0); | 998 | sys_bail(0); |
999 | } | 999 | } |
1000 | 1000 | ||
1001 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
1002 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
1003 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
1004 | |||
1005 | /* Pd side of the Pd/Pd-gui interface. Also, some system interface routines | ||
1006 | that didn't really belong anywhere. */ | ||
1007 | |||
1008 | #include "m_pd.h" | ||
1009 | #include "s_stuff.h" | ||
1010 | #include "m_imp.h" | ||
1011 | #ifdef UNIX | ||
1012 | #include <unistd.h> | ||
1013 | #include <sys/socket.h> | ||
1014 | #include <netinet/in.h> | ||
1015 | #include <netinet/tcp.h> | ||
1016 | #include <netdb.h> | ||
1017 | #include <stdlib.h> | ||
1018 | #include <sys/time.h> | ||
1019 | #include <sys/mman.h> | ||
1020 | #endif | ||
1021 | #ifdef HAVE_BSTRING_H | ||
1022 | #include <bstring.h> | ||
1023 | #endif | ||
1024 | #ifdef MSW | ||
1025 | #include <io.h> | ||
1026 | #include <fcntl.h> | ||
1027 | #include <process.h> | ||
1028 | #include <winsock.h> | ||
1029 | typedef int pid_t; | ||
1030 | #define EADDRINUSE WSAEADDRINUSE | ||
1031 | #endif | ||
1032 | #include <stdarg.h> | ||
1033 | #include <signal.h> | ||
1034 | #include <fcntl.h> | ||
1035 | #include <errno.h> | ||
1036 | #include <string.h> | ||
1037 | #include <stdio.h> | ||
1038 | |||
1039 | #ifdef MACOSX | ||
1040 | #include <sys/types.h> | ||
1041 | #include <sys/stat.h> | ||
1042 | #include <pthread.h> | ||
1043 | #else | ||
1044 | #include <stdlib.h> | ||
1045 | #endif | ||
1046 | |||
1047 | #define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */ | ||
1048 | #define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */ | ||
1049 | |||
1050 | /* T.Grill - make it a _little_ more adaptable... */ | ||
1051 | #ifndef PDBINDIR | ||
1052 | #define PDBINDIR "bin/" | ||
1053 | #endif | ||
1054 | |||
1055 | #ifndef WISHAPP | ||
1056 | #define WISHAPP "wish83.exe" | ||
1057 | #endif | ||
1058 | |||
1059 | extern char pd_version[]; | ||
1060 | |||
1061 | typedef struct _fdpoll | ||
1062 | { | ||
1063 | int fdp_fd; | ||
1064 | t_fdpollfn fdp_fn; | ||
1065 | void *fdp_ptr; | ||
1066 | } t_fdpoll; | ||
1067 | |||
1068 | #define INBUFSIZE 4096 | ||
1069 | |||
1070 | struct _socketreceiver | ||
1071 | { | ||
1072 | char *sr_inbuf; | ||
1073 | int sr_inhead; | ||
1074 | int sr_intail; | ||
1075 | void *sr_owner; | ||
1076 | int sr_udp; | ||
1077 | t_socketnotifier sr_notifier; | ||
1078 | t_socketreceivefn sr_socketreceivefn; | ||
1079 | }; | ||
1080 | |||
1081 | static int sys_nfdpoll; | ||
1082 | static t_fdpoll *sys_fdpoll; | ||
1083 | static int sys_maxfd; | ||
1084 | static int sys_guisock; | ||
1085 | |||
1086 | static t_binbuf *inbinbuf; | ||
1087 | static t_socketreceiver *sys_socketreceiver; | ||
1088 | extern int sys_addhist(int phase); | ||
1089 | |||
1090 | #ifdef MSW | ||
1091 | static LARGE_INTEGER nt_inittime; | ||
1092 | static double nt_freq = 0; | ||
1093 | |||
1094 | static void sys_initntclock(void) | ||
1095 | { | ||
1096 | LARGE_INTEGER f1; | ||
1097 | LARGE_INTEGER now; | ||
1098 | QueryPerformanceCounter(&now); | ||
1099 | if (!QueryPerformanceFrequency(&f1)) | ||
1100 | { | ||
1101 | fprintf(stderr, "pd: QueryPerformanceFrequency failed\n"); | ||
1102 | f1.QuadPart = 1; | ||
1103 | } | ||
1104 | nt_freq = f1.QuadPart; | ||
1105 | nt_inittime = now; | ||
1106 | } | ||
1107 | |||
1108 | #if 0 | ||
1109 | /* this is a version you can call if you did the QueryPerformanceCounter | ||
1110 | call yourself. Necessary for time tagging incoming MIDI at interrupt | ||
1111 | level, for instance; but we're not doing that just now. */ | ||
1112 | |||
1113 | double nt_tixtotime(LARGE_INTEGER *dumbass) | ||
1114 | { | ||
1115 | if (nt_freq == 0) sys_initntclock(); | ||
1116 | return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq); | ||
1117 | } | ||
1118 | #endif | ||
1119 | #endif /* MSW */ | ||
1120 | |||
1121 | /* get "real time" in seconds; take the | ||
1122 | first time we get called as a reference time of zero. */ | ||
1123 | t_time sys_getrealtime(void) | ||
1124 | { | ||
1125 | #ifdef UNIX | ||
1126 | static struct timeval then; | ||
1127 | struct timeval now; | ||
1128 | gettimeofday(&now, 0); | ||
1129 | if (then.tv_sec == 0 && then.tv_usec == 0) then = now; | ||
1130 | return (now.tv_sec - then.tv_sec)*1000000 + | ||
1131 | (now.tv_usec - then.tv_usec); | ||
1132 | #endif | ||
1133 | #ifdef MSW | ||
1134 | LARGE_INTEGER now; | ||
1135 | QueryPerformanceCounter(&now); | ||
1136 | if (nt_freq == 0) sys_initntclock(); | ||
1137 | return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq); | ||
1138 | #endif | ||
1139 | } | ||
1140 | |||
1141 | void sys_sockerror(char *s) | ||
1142 | { | ||
1143 | #ifdef MSW | ||
1144 | int err = WSAGetLastError(); | ||
1145 | if (err == 10054) return; | ||
1146 | else if (err == 10044) | ||
1147 | { | ||
1148 | fprintf(stderr, | ||
1149 | "Warning: you might not have TCP/IP \"networking\" turned on\n"); | ||
1150 | fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n"); | ||
1151 | } | ||
1152 | #endif | ||
1153 | #ifdef UNIX | ||
1154 | int err = errno; | ||
1155 | #endif | ||
1156 | fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err); | ||
1157 | } | ||
1158 | |||
1159 | void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr) | ||
1160 | { | ||
1161 | int nfd = sys_nfdpoll; | ||
1162 | int size = nfd * sizeof(t_fdpoll); | ||
1163 | t_fdpoll *fp; | ||
1164 | sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, | ||
1165 | size + sizeof(t_fdpoll)); | ||
1166 | fp = sys_fdpoll + nfd; | ||
1167 | fp->fdp_fd = fd; | ||
1168 | fp->fdp_fn = fn; | ||
1169 | fp->fdp_ptr = ptr; | ||
1170 | sys_nfdpoll = nfd + 1; | ||
1171 | if (fd >= sys_maxfd) sys_maxfd = fd + 1; | ||
1172 | } | ||
1173 | |||
1174 | void sys_rmpollfn(int fd) | ||
1175 | { | ||
1176 | int nfd = sys_nfdpoll; | ||
1177 | int i, size = nfd * sizeof(t_fdpoll); | ||
1178 | t_fdpoll *fp; | ||
1179 | for (i = nfd, fp = sys_fdpoll; i--; fp++) | ||
1180 | { | ||
1181 | if (fp->fdp_fd == fd) | ||
1182 | { | ||
1183 | while (i--) | ||
1184 | { | ||
1185 | fp[0] = fp[1]; | ||
1186 | fp++; | ||
1187 | } | ||
1188 | sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, | ||
1189 | size - sizeof(t_fdpoll)); | ||
1190 | sys_nfdpoll = nfd - 1; | ||
1191 | return; | ||
1192 | } | ||
1193 | } | ||
1194 | post("warning: %d removed from poll list but not found", fd); | ||
1195 | } | ||
1196 | |||
1197 | static int sys_domicrosleep(int microsec, int pollem) | ||
1198 | { | ||
1199 | struct timeval timout; | ||
1200 | int i, didsomething = 0; | ||
1201 | t_fdpoll *fp; | ||
1202 | timout.tv_sec = 0; | ||
1203 | timout.tv_usec = microsec; | ||
1204 | if (pollem) | ||
1205 | { | ||
1206 | fd_set readset, writeset, exceptset; | ||
1207 | FD_ZERO(&writeset); | ||
1208 | FD_ZERO(&readset); | ||
1209 | FD_ZERO(&exceptset); | ||
1210 | for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++) | ||
1211 | FD_SET(fp->fdp_fd, &readset); | ||
1212 | select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout); | ||
1213 | for (i = 0; i < sys_nfdpoll; i++) | ||
1214 | if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset)) | ||
1215 | { | ||
1216 | (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd); | ||
1217 | didsomething = 1; | ||
1218 | } | ||
1219 | return (didsomething); | ||
1220 | } | ||
1221 | else | ||
1222 | { | ||
1223 | select(0, 0, 0, 0, &timout); | ||
1224 | return (0); | ||
1225 | } | ||
1226 | } | ||
1227 | |||
1228 | void sys_microsleep(int microsec) | ||
1229 | { | ||
1230 | sys_domicrosleep(microsec, 1); | ||
1231 | } | ||
1232 | |||
1233 | t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier, | ||
1234 | t_socketreceivefn socketreceivefn, int udp) | ||
1235 | { | ||
1236 | t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x)); | ||
1237 | x->sr_inhead = x->sr_intail = 0; | ||
1238 | x->sr_owner = owner; | ||
1239 | x->sr_notifier = notifier; | ||
1240 | x->sr_socketreceivefn = socketreceivefn; | ||
1241 | x->sr_udp = udp; | ||
1242 | if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_socketreceiver");; | ||
1243 | return (x); | ||
1244 | } | ||
1245 | |||
1246 | void socketreceiver_free(t_socketreceiver *x) | ||
1247 | { | ||
1248 | free(x->sr_inbuf); | ||
1249 | freebytes(x, sizeof(*x)); | ||
1250 | } | ||
1251 | |||
1252 | /* this is in a separately called subroutine so that the buffer isn't | ||
1253 | sitting on the stack while the messages are getting passed. */ | ||
1254 | static int socketreceiver_doread(t_socketreceiver *x) | ||
1255 | { | ||
1256 | char messbuf[INBUFSIZE], *bp = messbuf; | ||
1257 | int indx; | ||
1258 | int inhead = x->sr_inhead; | ||
1259 | int intail = x->sr_intail; | ||
1260 | char *inbuf = x->sr_inbuf; | ||
1261 | if (intail == inhead) return (0); | ||
1262 | for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) | ||
1263 | { | ||
1264 | /* if we hit a semi that isn't preceeded by a \, it's a message | ||
1265 | boundary. LATER we should deal with the possibility that the | ||
1266 | preceeding \ might itself be escaped! */ | ||
1267 | char c = *bp++ = inbuf[indx]; | ||
1268 | if (c == ';' && (!indx || inbuf[indx-1] != '\\')) | ||
1269 | { | ||
1270 | intail = (indx+1)&(INBUFSIZE-1); | ||
1271 | binbuf_text(inbinbuf, messbuf, bp - messbuf); | ||
1272 | if (sys_debuglevel & DEBUG_MESSDOWN) | ||
1273 | { | ||
1274 | write(2, messbuf, bp - messbuf); | ||
1275 | write(2, "\n", 1); | ||
1276 | } | ||
1277 | x->sr_inhead = inhead; | ||
1278 | x->sr_intail = intail; | ||
1279 | return (1); | ||
1280 | } | ||
1281 | } | ||
1282 | return (0); | ||
1283 | } | ||
1284 | |||
1285 | static void socketreceiver_getudp(t_socketreceiver *x, int fd) | ||
1286 | { | ||
1287 | char buf[INBUFSIZE+1]; | ||
1288 | int ret = recv(fd, buf, INBUFSIZE, 0); | ||
1289 | if (ret < 0) | ||
1290 | { | ||
1291 | sys_sockerror("recv"); | ||
1292 | sys_rmpollfn(fd); | ||
1293 | sys_closesocket(fd); | ||
1294 | } | ||
1295 | else if (ret > 0) | ||
1296 | { | ||
1297 | buf[ret] = 0; | ||
1298 | #if 0 | ||
1299 | post("%s", buf); | ||
1300 | #endif | ||
1301 | if (buf[ret-1] != '\n') | ||
1302 | { | ||
1303 | #if 0 | ||
1304 | buf[ret] = 0; | ||
1305 | error("dropped bad buffer %s\n", buf); | ||
1306 | #endif | ||
1307 | } | ||
1308 | else | ||
1309 | { | ||
1310 | char *semi = strchr(buf, ';'); | ||
1311 | if (semi) | ||
1312 | *semi = 0; | ||
1313 | binbuf_text(inbinbuf, buf, strlen(buf)); | ||
1314 | outlet_setstacklim(); | ||
1315 | if (x->sr_socketreceivefn) | ||
1316 | (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); | ||
1317 | else bug("socketreceiver_getudp"); | ||
1318 | } | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | |||
1323 | |||
1324 | #include <termios.h> | ||
1325 | #include <string.h> | ||
1326 | |||
1327 | static struct termios stored_settings; | ||
1328 | EXTERN int sys_stdin; | ||
1329 | |||
1330 | void set_keypress(void) | ||
1331 | { | ||
1332 | struct termios new_settings; | ||
1333 | |||
1334 | tcgetattr(0,&stored_settings); | ||
1335 | |||
1336 | new_settings = stored_settings; | ||
1337 | |||
1338 | /* Disable canonical mode, and set buffer size to 1 byte */ | ||
1339 | new_settings.c_lflag &= (~ICANON); | ||
1340 | new_settings.c_cc[VTIME] = 0; | ||
1341 | new_settings.c_cc[VMIN] = 1; | ||
1342 | |||
1343 | /* echo off */ | ||
1344 | new_settings.c_lflag &= (~ECHO); | ||
1345 | |||
1346 | tcsetattr(0,TCSANOW,&new_settings); | ||
1347 | return; | ||
1348 | } | ||
1349 | |||
1350 | void reset_keypress(void) | ||
1351 | { | ||
1352 | if (sys_stdin) | ||
1353 | tcsetattr(0,TCSANOW,&stored_settings); | ||
1354 | return; | ||
1355 | } | ||
1356 | |||
1357 | static t_symbol* _ss; | ||
1358 | |||
1359 | |||
1360 | void stdin_read(t_socketreceiver *x, int fd) { | ||
1361 | static char input[256]; | ||
1362 | |||
1363 | char* in; | ||
1364 | int got; | ||
1365 | |||
1366 | got = read(fd,input,256); | ||
1367 | in = input; | ||
1368 | while (got-- && _ss->s_thing) | ||
1369 | pd_float(_ss->s_thing,(float)*in++); | ||
1370 | } | ||
1371 | |||
1372 | void socketreceiver_read(t_socketreceiver *x, int fd) | ||
1373 | { | ||
1374 | if (x->sr_udp) /* UDP ("datagram") socket protocol */ | ||
1375 | socketreceiver_getudp(x, fd); | ||
1376 | else /* TCP ("streaming") socket protocol */ | ||
1377 | { | ||
1378 | char *semi; | ||
1379 | int readto = | ||
1380 | (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); | ||
1381 | int ret; | ||
1382 | |||
1383 | /* the input buffer might be full. If so, drop the whole thing */ | ||
1384 | if (readto == x->sr_inhead) | ||
1385 | { | ||
1386 | fprintf(stderr, "pd: dropped message from gui\n"); | ||
1387 | x->sr_inhead = x->sr_intail = 0; | ||
1388 | readto = INBUFSIZE; | ||
1389 | } | ||
1390 | else | ||
1391 | { | ||
1392 | ret = recv(fd, x->sr_inbuf + x->sr_inhead, | ||
1393 | readto - x->sr_inhead, 0); | ||
1394 | if (ret < 0) | ||
1395 | { | ||
1396 | sys_sockerror("recv"); | ||
1397 | if (x == sys_socketreceiver) sys_bail(1); | ||
1398 | else | ||
1399 | { | ||
1400 | if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); | ||
1401 | sys_rmpollfn(fd); | ||
1402 | sys_closesocket(fd); | ||
1403 | } | ||
1404 | } | ||
1405 | else if (ret == 0) | ||
1406 | { | ||
1407 | if (x == sys_socketreceiver) | ||
1408 | { | ||
1409 | fprintf(stderr, "pd: exiting\n"); | ||
1410 | sys_bail(0); | ||
1411 | } | ||
1412 | else | ||
1413 | { | ||
1414 | post("EOF on socket %d\n", fd); | ||
1415 | if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); | ||
1416 | sys_rmpollfn(fd); | ||
1417 | sys_closesocket(fd); | ||
1418 | } | ||
1419 | } | ||
1420 | else | ||
1421 | { | ||
1422 | x->sr_inhead += ret; | ||
1423 | if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; | ||
1424 | while (socketreceiver_doread(x)) | ||
1425 | { | ||
1426 | outlet_setstacklim(); | ||
1427 | if (x->sr_socketreceivefn) | ||
1428 | (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); | ||
1429 | else binbuf_eval(inbinbuf, 0, 0, 0); | ||
1430 | } | ||
1431 | } | ||
1432 | } | ||
1433 | } | ||
1434 | } | ||
1435 | |||
1436 | void sys_closesocket(int fd) | ||
1437 | { | ||
1438 | #ifdef UNIX | ||
1439 | close(fd); | ||
1440 | #endif | ||
1441 | #ifdef MSW | ||
1442 | closesocket(fd); | ||
1443 | #endif | ||
1444 | } | ||
1445 | |||
1446 | |||
1447 | void sys_gui(char *s) | ||
1448 | { | ||
1449 | int length = strlen(s), written = 0, res, histwas = sys_addhist(4); | ||
1450 | if (sys_debuglevel & DEBUG_MESSUP) | ||
1451 | fprintf(stderr, "%s", s); | ||
1452 | if (sys_nogui) | ||
1453 | return; | ||
1454 | while (1) | ||
1455 | { | ||
1456 | res = send(sys_guisock, s + written, length, 0); | ||
1457 | if (res < 0) | ||
1458 | { | ||
1459 | perror("pd output pipe"); | ||
1460 | sys_bail(1); | ||
1461 | } | ||
1462 | else | ||
1463 | { | ||
1464 | written += res; | ||
1465 | if (written >= length) | ||
1466 | break; | ||
1467 | } | ||
1468 | } | ||
1469 | sys_addhist(histwas); | ||
1470 | } | ||
1471 | |||
1472 | /* LATER should do a bounds check -- but how do you get printf to do that? | ||
1473 | See also rtext_senditup() in this regard */ | ||
1474 | |||
1475 | void sys_vgui(char *fmt, ...) | ||
1476 | { | ||
1477 | int result, i; | ||
1478 | char buf[2048]; | ||
1479 | va_list ap; | ||
1480 | |||
1481 | va_start(ap, fmt); | ||
1482 | vsprintf(buf, fmt, ap); | ||
1483 | sys_gui(buf); | ||
1484 | va_end(ap); | ||
1485 | } | ||
1486 | |||
1487 | |||
1488 | #define FIRSTPORTNUM 5400 | ||
1489 | |||
1490 | /* -------------- signal handling for UNIX -------------- */ | ||
1491 | |||
1492 | #ifdef UNIX | ||
1493 | typedef void (*sighandler_t)(int); | ||
1494 | |||
1495 | static void sys_signal(int signo, sighandler_t sigfun) | ||
1496 | { | ||
1497 | struct sigaction action; | ||
1498 | action.sa_flags = 0; | ||
1499 | action.sa_handler = sigfun; | ||
1500 | memset(&action.sa_mask, 0, sizeof(action.sa_mask)); | ||
1501 | #if 0 /* GG says: don't use that */ | ||
1502 | action.sa_restorer = 0; | ||
1503 | #endif | ||
1504 | if (sigaction(signo, &action, 0) < 0) | ||
1505 | perror("sigaction"); | ||
1506 | } | ||
1507 | |||
1508 | static void sys_exithandler(int n) | ||
1509 | { | ||
1510 | static int trouble = 0; | ||
1511 | if (!trouble) | ||
1512 | { | ||
1513 | trouble = 1; | ||
1514 | fprintf(stderr, "Pd: signal %d\n", n); | ||
1515 | sys_bail(1); | ||
1516 | |||
1517 | } | ||
1518 | else _exit(1); | ||
1519 | } | ||
1520 | |||
1521 | static void sys_alarmhandler(int n) | ||
1522 | { | ||
1523 | fprintf(stderr, "Pd: system call timed out\n"); | ||
1524 | } | ||
1525 | |||
1526 | static void sys_huphandler(int n) | ||
1527 | { | ||
1528 | struct timeval timout; | ||
1529 | timout.tv_sec = 0; | ||
1530 | timout.tv_usec = 30000; | ||
1531 | select(1, 0, 0, 0, &timout); | ||
1532 | } | ||
1533 | |||
1534 | void sys_setalarm(int microsec) | ||
1535 | { | ||
1536 | struct itimerval gonzo; | ||
1537 | #if 0 | ||
1538 | fprintf(stderr, "timer %d\n", microsec); | ||
1539 | #endif | ||
1540 | gonzo.it_interval.tv_sec = 0; | ||
1541 | gonzo.it_interval.tv_usec = 0; | ||
1542 | gonzo.it_value.tv_sec = 0; | ||
1543 | gonzo.it_value.tv_usec = microsec; | ||
1544 | if (microsec) | ||
1545 | sys_signal(SIGALRM, sys_alarmhandler); | ||
1546 | else sys_signal(SIGALRM, SIG_IGN); | ||
1547 | setitimer(ITIMER_REAL, &gonzo, 0); | ||
1548 | } | ||
1549 | |||
1550 | #endif | ||
1551 | |||
1552 | #ifdef __linux__ | ||
1553 | |||
1554 | #if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK) | ||
1555 | #include <sched.h> | ||
1556 | #endif | ||
1557 | |||
1558 | void sys_set_priority(int higher) | ||
1559 | { | ||
1560 | #ifdef _POSIX_PRIORITY_SCHEDULING | ||
1561 | struct sched_param par; | ||
1562 | int p1 ,p2, p3; | ||
1563 | p1 = sched_get_priority_min(SCHED_FIFO); | ||
1564 | p2 = sched_get_priority_max(SCHED_FIFO); | ||
1565 | #ifdef USEAPI_JACK | ||
1566 | p3 = (higher ? p1 + 7 : p1 + 5); | ||
1567 | #else | ||
1568 | p3 = (higher ? p2 - 1 : p2 - 3); | ||
1569 | #endif | ||
1570 | par.sched_priority = p3; | ||
1571 | if (sched_setscheduler(0,SCHED_FIFO,&par) != -1) | ||
1572 | fprintf(stderr, "priority %d scheduling enabled.\n", p3); | ||
1573 | #endif | ||
1574 | |||
1575 | #ifdef _POSIX_MEMLOCK | ||
1576 | if (mlockall(MCL_FUTURE) != -1) | ||
1577 | fprintf(stderr, "memory locking enabled.\n"); | ||
1578 | #endif | ||
1579 | |||
1580 | } | ||
1581 | |||
1582 | #endif /* __linux__ */ | ||
1583 | |||
1584 | static int sys_watchfd; | ||
1585 | |||
1586 | #ifdef __linux__ | ||
1587 | void glob_ping(t_pd *dummy) | ||
1588 | { | ||
1589 | if (write(sys_watchfd, "\n", 1) < 1) | ||
1590 | { | ||
1591 | fprintf(stderr, "pd: watchdog process died\n"); | ||
1592 | sys_bail(1); | ||
1593 | } | ||
1594 | } | ||
1595 | #endif | ||
1596 | |||
1597 | static int defaultfontshit[] = { | ||
1598 | 8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28, | ||
1599 | 24, 15, 28}; | ||
1600 | |||
1601 | int sys_startgui(const char *guidir) | ||
1602 | { | ||
1603 | pid_t childpid; | ||
1604 | char cmdbuf[4*MAXPDSTRING]; | ||
1605 | struct sockaddr_in server; | ||
1606 | int msgsock; | ||
1607 | char buf[15]; | ||
1608 | int len = sizeof(server); | ||
1609 | int ntry = 0, portno = FIRSTPORTNUM; | ||
1610 | int xsock = -1; | ||
1611 | #ifdef MSW | ||
1612 | short version = MAKEWORD(2, 0); | ||
1613 | WSADATA nobby; | ||
1614 | #endif | ||
1615 | #ifdef UNIX | ||
1616 | int stdinpipe[2]; | ||
1617 | #endif | ||
1618 | /* create an empty FD poll list */ | ||
1619 | sys_fdpoll = (t_fdpoll *)t_getbytes(0); | ||
1620 | sys_nfdpoll = 0; | ||
1621 | inbinbuf = binbuf_new(); | ||
1622 | |||
1623 | #ifdef UNIX | ||
1624 | signal(SIGHUP, sys_huphandler); | ||
1625 | signal(SIGINT, sys_exithandler); | ||
1626 | signal(SIGQUIT, sys_exithandler); | ||
1627 | signal(SIGILL, sys_exithandler); | ||
1628 | signal(SIGIOT, sys_exithandler); | ||
1629 | signal(SIGFPE, SIG_IGN); | ||
1630 | /* signal(SIGILL, sys_exithandler); | ||
1631 | signal(SIGBUS, sys_exithandler); | ||
1632 | signal(SIGSEGV, sys_exithandler); */ | ||
1633 | signal(SIGPIPE, SIG_IGN); | ||
1634 | signal(SIGALRM, SIG_IGN); | ||
1635 | signal(SIGTERM, SIG_IGN); | ||
1636 | #if 0 /* GG says: don't use that */ | ||
1637 | signal(SIGSTKFLT, sys_exithandler); | ||
1638 | #endif | ||
1639 | #endif | ||
1640 | #ifdef MSW | ||
1641 | if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup"); | ||
1642 | #endif | ||
1643 | |||
1644 | if (sys_nogui) | ||
1645 | { | ||
1646 | /* fake the GUI's message giving cwd and font sizes; then | ||
1647 | skip starting the GUI up. */ | ||
1648 | t_atom zz[19]; | ||
1649 | int i; | ||
1650 | #ifdef MSW | ||
1651 | if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0) | ||
1652 | strcpy(cmdbuf, "."); | ||
1653 | #endif | ||
1654 | #ifdef UNIX | ||
1655 | if (!getcwd(cmdbuf, MAXPDSTRING)) | ||
1656 | strcpy(cmdbuf, "."); | ||
1657 | |||
1658 | #endif | ||
1659 | SETSYMBOL(zz, gensym(cmdbuf)); | ||
1660 | for (i = 1; i < 22; i++) | ||
1661 | SETFLOAT(zz + i, defaultfontshit[i-1]); | ||
1662 | SETFLOAT(zz+22,0); | ||
1663 | glob_initfromgui(0, 0, 23, zz); | ||
1664 | } | ||
1665 | else | ||
1666 | { | ||
1667 | #ifdef MSW | ||
1668 | char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80]; | ||
1669 | int spawnret; | ||
1670 | |||
1671 | #endif | ||
1672 | #ifdef MSW | ||
1673 | char intarg; | ||
1674 | #else | ||
1675 | int intarg; | ||
1676 | #endif | ||
1677 | |||
1678 | /* create a socket */ | ||
1679 | xsock = socket(AF_INET, SOCK_STREAM, 0); | ||
1680 | if (xsock < 0) sys_sockerror("socket"); | ||
1681 | #if 0 | ||
1682 | intarg = 0; | ||
1683 | if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF, | ||
1684 | &intarg, sizeof(intarg)) < 0) | ||
1685 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
1686 | intarg = 0; | ||
1687 | if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF, | ||
1688 | &intarg, sizeof(intarg)) < 0) | ||
1689 | post("setsockopt (SO_RCVBUF) failed\n"); | ||
1690 | #endif | ||
1691 | intarg = 1; | ||
1692 | if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY, | ||
1693 | &intarg, sizeof(intarg)) < 0) | ||
1694 | #ifndef MSW | ||
1695 | post("setsockopt (TCP_NODELAY) failed\n") | ||
1696 | #endif | ||
1697 | ; | ||
1698 | |||
1699 | |||
1700 | server.sin_family = AF_INET; | ||
1701 | server.sin_addr.s_addr = INADDR_ANY; | ||
1702 | |||
1703 | /* assign server port number */ | ||
1704 | server.sin_port = htons((unsigned short)portno); | ||
1705 | |||
1706 | /* name the socket */ | ||
1707 | while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0) | ||
1708 | { | ||
1709 | #ifdef MSW | ||
1710 | int err = WSAGetLastError(); | ||
1711 | #endif | ||
1712 | #ifdef UNIX | ||
1713 | int err = errno; | ||
1714 | #endif | ||
1715 | if ((ntry++ > 20) || (err != EADDRINUSE)) | ||
1716 | { | ||
1717 | perror("bind"); | ||
1718 | fprintf(stderr, | ||
1719 | "Pd needs your machine to be configured with\n"); | ||
1720 | fprintf(stderr, | ||
1721 | "'networking' turned on (see Pd's html doc for details.)\n"); | ||
1722 | exit(1); | ||
1723 | } | ||
1724 | portno++; | ||
1725 | server.sin_port = htons((unsigned short)(portno)); | ||
1726 | } | ||
1727 | |||
1728 | if (sys_verbose) fprintf(stderr, "port %d\n", portno); | ||
1729 | |||
1730 | sys_socketreceiver = socketreceiver_new(0, 0, 0, 0); | ||
1731 | |||
1732 | #ifdef UNIX | ||
1733 | childpid = fork(); | ||
1734 | if (childpid < 0) | ||
1735 | { | ||
1736 | if (errno) perror("sys_startgui"); | ||
1737 | else fprintf(stderr, "sys_startgui failed\n"); | ||
1738 | return (1); | ||
1739 | } | ||
1740 | else if (!childpid) /* we're the child */ | ||
1741 | { | ||
1742 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1743 | #ifndef MACOSX | ||
1744 | /* the wish process in Unix will make a wish shell and | ||
1745 | read/write standard in and out unless we close the | ||
1746 | file descriptors. Somehow this doesn't make the MAC OSX | ||
1747 | version of Wish happy...*/ | ||
1748 | if (pipe(stdinpipe) < 0) | ||
1749 | sys_sockerror("pipe"); | ||
1750 | else | ||
1751 | { | ||
1752 | if (stdinpipe[0] != 0) | ||
1753 | { | ||
1754 | close (0); | ||
1755 | dup2(stdinpipe[0], 0); | ||
1756 | close(stdinpipe[0]); | ||
1757 | } | ||
1758 | } | ||
1759 | #endif | ||
1760 | if (!sys_guicmd) | ||
1761 | { | ||
1762 | #ifdef MACOSX | ||
1763 | char *homedir = getenv("HOME"), filename[250]; | ||
1764 | struct stat statbuf; | ||
1765 | if (!homedir || strlen(homedir) > 150) | ||
1766 | goto nohomedir; | ||
1767 | sprintf(filename, | ||
1768 | "%s/Applications/Utilities/Wish shell.app/Contents/MacOS/Wish Shell", | ||
1769 | homedir); | ||
1770 | if (stat(filename, &statbuf) >= 0) | ||
1771 | goto foundit; | ||
1772 | sprintf(filename, | ||
1773 | "%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell", | ||
1774 | homedir); | ||
1775 | if (stat(filename, &statbuf) >= 0) | ||
1776 | goto foundit; | ||
1777 | nohomedir: | ||
1778 | strcpy(filename, | ||
1779 | "/Applications/Utilities/Wish Shell.app/Contents/MacOS/Wish Shell"); | ||
1780 | if (stat(filename, &statbuf) >= 0) | ||
1781 | goto foundit; | ||
1782 | strcpy(filename, | ||
1783 | "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell"); | ||
1784 | foundit: | ||
1785 | sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno); | ||
1786 | #else | ||
1787 | sprintf(cmdbuf, | ||
1788 | "TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \ | ||
1789 | \"%s/pd-gui\" %d\n", | ||
1790 | sys_libdir->s_name, sys_libdir->s_name, guidir, portno); | ||
1791 | #endif | ||
1792 | sys_guicmd = cmdbuf; | ||
1793 | } | ||
1794 | if (sys_verbose) fprintf(stderr, "%s", sys_guicmd); | ||
1795 | execl("/bin/sh", "sh", "-c", sys_guicmd, 0); | ||
1796 | perror("pd: exec"); | ||
1797 | _exit(1); | ||
1798 | } | ||
1799 | #endif /* UNIX */ | ||
1800 | |||
1801 | #ifdef MSW | ||
1802 | /* in MSW land "guipath" is unused; we just do everything from | ||
1803 | the libdir. */ | ||
1804 | /* fprintf(stderr, "%s\n", sys_libdir->s_name); */ | ||
1805 | |||
1806 | strcpy(scriptbuf, "\""); | ||
1807 | strcat(scriptbuf, sys_libdir->s_name); | ||
1808 | strcat(scriptbuf, "/" PDBINDIR "pd.tk\""); | ||
1809 | sys_bashfilename(scriptbuf, scriptbuf); | ||
1810 | |||
1811 | sprintf(portbuf, "%d", portno); | ||
1812 | |||
1813 | strcpy(wishbuf, sys_libdir->s_name); | ||
1814 | strcat(wishbuf, "/" PDBINDIR WISHAPP); | ||
1815 | sys_bashfilename(wishbuf, wishbuf); | ||
1816 | |||
1817 | spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0); | ||
1818 | if (spawnret < 0) | ||
1819 | { | ||
1820 | perror("spawnl"); | ||
1821 | fprintf(stderr, "%s: couldn't load TCL\n", wishbuf); | ||
1822 | exit(1); | ||
1823 | } | ||
1824 | |||
1825 | #endif /* MSW */ | ||
1826 | } | ||
1827 | |||
1828 | #ifdef __linux__ | ||
1829 | /* now that we've spun off the child process we can promote | ||
1830 | our process's priority, if we happen to be root. */ | ||
1831 | if (sys_hipriority) | ||
1832 | { | ||
1833 | if (!getuid() || !geteuid()) | ||
1834 | { | ||
1835 | /* To prevent lockup, we fork off a watchdog process with | ||
1836 | higher real-time priority than ours. The GUI has to send | ||
1837 | a stream of ping messages to the watchdog THROUGH the Pd | ||
1838 | process which has to pick them up from the GUI and forward | ||
1839 | them. If any of these things aren't happening the watchdog | ||
1840 | starts sending "stop" and "cont" signals to the Pd process | ||
1841 | to make it timeshare with the rest of the system. (Version | ||
1842 | 0.33P2 : if there's no GUI, the watchdog pinging is done | ||
1843 | from the scheduler idle routine in this process instead.) */ | ||
1844 | |||
1845 | int pipe9[2], watchpid; | ||
1846 | if (pipe(pipe9) < 0) | ||
1847 | { | ||
1848 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1849 | sys_sockerror("pipe"); | ||
1850 | return (1); | ||
1851 | } | ||
1852 | watchpid = fork(); | ||
1853 | if (watchpid < 0) | ||
1854 | { | ||
1855 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1856 | if (errno) | ||
1857 | perror("sys_startgui"); | ||
1858 | else fprintf(stderr, "sys_startgui failed\n"); | ||
1859 | return (1); | ||
1860 | } | ||
1861 | else if (!watchpid) /* we're the child */ | ||
1862 | { | ||
1863 | sys_set_priority(1); | ||
1864 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1865 | if (pipe9[1] != 0) | ||
1866 | { | ||
1867 | dup2(pipe9[0], 0); | ||
1868 | close(pipe9[0]); | ||
1869 | } | ||
1870 | close(pipe9[1]); | ||
1871 | |||
1872 | sprintf(cmdbuf, "%s/pd-watchdog\n", guidir); | ||
1873 | if (sys_verbose) fprintf(stderr, "%s", cmdbuf); | ||
1874 | execl("/bin/sh", "sh", "-c", cmdbuf, 0); | ||
1875 | perror("pd: exec"); | ||
1876 | _exit(1); | ||
1877 | } | ||
1878 | else /* we're the parent */ | ||
1879 | { | ||
1880 | sys_set_priority(0); | ||
1881 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1882 | close(pipe9[0]); | ||
1883 | sys_watchfd = pipe9[1]; | ||
1884 | /* We also have to start the ping loop in the GUI; | ||
1885 | this is done later when the socket is open. */ | ||
1886 | } | ||
1887 | } | ||
1888 | else | ||
1889 | { | ||
1890 | post("realtime setting failed because not root\n"); | ||
1891 | sys_hipriority = 0; | ||
1892 | } | ||
1893 | } | ||
1894 | |||
1895 | seteuid(getuid()); /* lose setuid priveliges */ | ||
1896 | #endif /* __linux__ */ | ||
1897 | |||
1898 | #ifdef MSW | ||
1899 | if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) | ||
1900 | fprintf(stderr, "pd: couldn't set high priority class\n"); | ||
1901 | #endif | ||
1902 | #ifdef MACOSX | ||
1903 | if (sys_hipriority) | ||
1904 | { | ||
1905 | struct sched_param param; | ||
1906 | int policy = SCHED_RR; | ||
1907 | int err; | ||
1908 | param.sched_priority = 80; // adjust 0 : 100 | ||
1909 | |||
1910 | err = pthread_setschedparam(pthread_self(), policy, ¶m); | ||
1911 | if (err) | ||
1912 | post("warning: high priority scheduling failed\n"); | ||
1913 | } | ||
1914 | #endif /* MACOSX */ | ||
1915 | |||
1916 | if (!sys_nogui) | ||
1917 | { | ||
1918 | char buf[256]; | ||
1919 | if (sys_verbose) | ||
1920 | fprintf(stderr, "Waiting for connection request... \n"); | ||
1921 | if (listen(xsock, 5) < 0) sys_sockerror("listen"); | ||
1922 | |||
1923 | sys_guisock = accept(xsock, (struct sockaddr *) &server, &len); | ||
1924 | #ifdef OOPS | ||
1925 | close(xsock); | ||
1926 | #endif | ||
1927 | if (sys_guisock < 0) sys_sockerror("accept"); | ||
1928 | sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read, | ||
1929 | sys_socketreceiver); | ||
1930 | |||
1931 | if (sys_verbose) | ||
1932 | fprintf(stderr, "... connected\n"); | ||
1933 | |||
1934 | /* here is where we start the pinging. */ | ||
1935 | #ifdef __linux__ | ||
1936 | if (sys_hipriority) | ||
1937 | sys_gui("pdtk_watchdog\n"); | ||
1938 | #endif | ||
1939 | sys_get_audio_apis(buf); | ||
1940 | sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf); | ||
1941 | } | ||
1942 | if (sys_stdin) { | ||
1943 | set_keypress(); | ||
1944 | _ss = gensym("stdin"); | ||
1945 | sys_addpollfn(1, (t_fdpollfn) stdin_read,NULL); | ||
1946 | } | ||
1947 | return (0); | ||
1948 | |||
1949 | } | ||
1950 | |||
1951 | |||
1952 | static int sys_poll_togui(void) | ||
1953 | { | ||
1954 | /* LATER use this to flush output buffer to gui */ | ||
1955 | return (0); | ||
1956 | } | ||
1957 | |||
1958 | int sys_pollgui(void) | ||
1959 | { | ||
1960 | return (sys_domicrosleep(0, 1) || sys_poll_togui()); | ||
1961 | } | ||
1962 | |||
1963 | |||
1964 | /* T.Grill - import clean quit function */ | ||
1965 | extern void sys_exit(void); | ||
1966 | |||
1967 | /* This is called when something bad has happened, like a segfault. | ||
1968 | Call glob_quit() below to exit cleanly. | ||
1969 | LATER try to save dirty documents even in the bad case. */ | ||
1970 | void sys_bail(int n) | ||
1971 | { | ||
1972 | static int reentered = 0; | ||
1973 | reset_keypress(); | ||
1974 | if (!reentered) | ||
1975 | { | ||
1976 | reentered = 1; | ||
1977 | #ifndef __linux /* sys_close_audio() hangs if you're in a signal? */ | ||
1978 | fprintf(stderr, "closing audio...\n"); | ||
1979 | sys_close_audio(); | ||
1980 | fprintf(stderr, "closing MIDI...\n"); | ||
1981 | sys_close_midi(); | ||
1982 | fprintf(stderr, "... done.\n"); | ||
1983 | #endif | ||
1984 | exit(1); | ||
1985 | } | ||
1986 | else _exit(n); | ||
1987 | } | ||
1988 | |||
1989 | void glob_quit(void *dummy) | ||
1990 | { | ||
1991 | sys_vgui("exit\n"); | ||
1992 | if (!sys_nogui) | ||
1993 | { | ||
1994 | close(sys_guisock); | ||
1995 | sys_rmpollfn(sys_guisock); | ||
1996 | } | ||
1997 | reset_keypress(); | ||
1998 | sys_bail(0); | ||
1999 | } | ||
2000 | |||