Fix some greedy sed changes in imported code. Also provide a sys/types.h for compatib...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / s_inter.c
blob9df9c82b409c6f434c3d0d149cbc99e2e6d46143
1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 /* Pd side of the Pd/Pd-gui interface. Also, some system interface routines
6 that didn't really belong anywhere. */
8 #include "m_pd.h"
9 #include "s_stuff.h"
10 #include "m_imp.h"
11 #ifdef UNIX
12 #include <unistd.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <netinet/tcp.h>
16 #include <netdb.h>
17 #include <stdlib.h>
18 #include <sys/time.h>
19 #include <sys/mman.h>
20 #endif
21 #ifdef HAVE_BSTRING_H
22 #include <bstring.h>
23 #endif
24 #ifdef MSW
25 #include <io.h>
26 #include <fcntl.h>
27 #include <process.h>
28 #include <winsock.h>
29 typedef int pid_t;
30 #define EADDRINUSE WSAEADDRINUSE
31 #endif
32 #include <stdarg.h>
33 #include <signal.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <stdio.h>
39 #ifdef MACOSX
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <pthread.h>
43 #else
44 #include <stdlib.h>
45 #endif
47 #define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */
48 #define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */
50 /* T.Grill - make it a _little_ more adaptable... */
51 #ifndef PDBINDIR
52 #define PDBINDIR "bin/"
53 #endif
55 #ifndef WISHAPP
56 #define WISHAPP "wish83.exe"
57 #endif
59 extern char pd_version[];
61 typedef struct _fdpoll
63 int fdp_fd;
64 t_fdpollfn fdp_fn;
65 void *fdp_ptr;
66 } t_fdpoll;
68 #define INBUFSIZE 4096
70 struct _socketreceiver
72 char *sr_inbuf;
73 int sr_inhead;
74 int sr_intail;
75 void *sr_owner;
76 int sr_udp;
77 t_socketnotifier sr_notifier;
78 t_socketreceivefn sr_socketreceivefn;
81 static int sys_nfdpoll;
82 static t_fdpoll *sys_fdpoll;
83 static int sys_maxfd;
84 static int sys_guisock;
86 static t_binbuf *inbinbuf;
87 static t_socketreceiver *sys_socketreceiver;
88 extern int sys_addhist(int phase);
90 #ifdef MSW
91 static LARGE_INTEGER nt_inittime;
92 static double nt_freq = 0;
94 static void sys_initntclock(void)
96 LARGE_INTEGER f1;
97 LARGE_INTEGER now;
98 QueryPerformanceCounter(&now);
99 if (!QueryPerformanceFrequency(&f1))
101 fprintf(stderr, "pd: QueryPerformanceFrequency failed\n");
102 f1.QuadPart = 1;
104 nt_freq = f1.QuadPart;
105 nt_inittime = now;
108 #if 0
109 /* this is a version you can call if you did the QueryPerformanceCounter
110 call yourself. Necessary for time tagging incoming MIDI at interrupt
111 level, for instance; but we're not doing that just now. */
113 double nt_tixtotime(LARGE_INTEGER *dumbass)
115 if (nt_freq == 0) sys_initntclock();
116 return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq);
118 #endif
119 #endif /* MSW */
121 /* get "real time" in seconds; take the
122 first time we get called as a reference time of zero. */
123 t_time sys_getrealtime(void)
125 #ifdef UNIX
126 static struct timeval then;
127 struct timeval now;
128 gettimeofday(&now, 0);
129 if (then.tv_sec == 0 && then.tv_usec == 0) then = now;
130 return (now.tv_sec - then.tv_sec)*1000000 +
131 (now.tv_usec - then.tv_usec);
132 #endif
133 #ifdef MSW
134 LARGE_INTEGER now;
135 QueryPerformanceCounter(&now);
136 if (nt_freq == 0) sys_initntclock();
137 return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq);
138 #endif
141 void sys_sockerror(char *s)
143 #ifdef MSW
144 int err = WSAGetLastError();
145 if (err == 10054) return;
146 else if (err == 10044)
148 fprintf(stderr,
149 "Warning: you might not have TCP/IP \"networking\" turned on\n");
150 fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n");
152 #endif
153 #ifdef UNIX
154 int err = errno;
155 #endif
156 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
159 void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr)
161 int nfd = sys_nfdpoll;
162 int size = nfd * sizeof(t_fdpoll);
163 t_fdpoll *fp;
164 sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
165 size + sizeof(t_fdpoll));
166 fp = sys_fdpoll + nfd;
167 fp->fdp_fd = fd;
168 fp->fdp_fn = fn;
169 fp->fdp_ptr = ptr;
170 sys_nfdpoll = nfd + 1;
171 if (fd >= sys_maxfd) sys_maxfd = fd + 1;
174 void sys_rmpollfn(int fd)
176 int nfd = sys_nfdpoll;
177 int i, size = nfd * sizeof(t_fdpoll);
178 t_fdpoll *fp;
179 for (i = nfd, fp = sys_fdpoll; i--; fp++)
181 if (fp->fdp_fd == fd)
183 while (i--)
185 fp[0] = fp[1];
186 fp++;
188 sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
189 size - sizeof(t_fdpoll));
190 sys_nfdpoll = nfd - 1;
191 return;
194 post("warning: %d removed from poll list but not found", fd);
197 static int sys_domicrosleep(int microsec, int pollem)
199 struct timeval timout;
200 int i, didsomething = 0;
201 t_fdpoll *fp;
202 timout.tv_sec = 0;
203 timout.tv_usec = microsec;
204 if (pollem)
206 fd_set readset, writeset, exceptset;
207 FD_ZERO(&writeset);
208 FD_ZERO(&readset);
209 FD_ZERO(&exceptset);
210 for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++)
211 FD_SET(fp->fdp_fd, &readset);
212 select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout);
213 for (i = 0; i < sys_nfdpoll; i++)
214 if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset))
216 (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd);
217 didsomething = 1;
219 return (didsomething);
221 else
223 select(0, 0, 0, 0, &timout);
224 return (0);
228 void sys_microsleep(int microsec)
230 sys_domicrosleep(microsec, 1);
233 t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier,
234 t_socketreceivefn socketreceivefn, int udp)
236 t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x));
237 x->sr_inhead = x->sr_intail = 0;
238 x->sr_owner = owner;
239 x->sr_notifier = notifier;
240 x->sr_socketreceivefn = socketreceivefn;
241 x->sr_udp = udp;
242 if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_socketreceiver");;
243 return (x);
246 void socketreceiver_free(t_socketreceiver *x)
248 free(x->sr_inbuf);
249 freebytes(x, sizeof(*x));
252 /* this is in a separately called subroutine so that the buffer isn't
253 sitting on the stack while the messages are getting passed. */
254 static int socketreceiver_doread(t_socketreceiver *x)
256 char messbuf[INBUFSIZE], *bp = messbuf;
257 int indx;
258 int inhead = x->sr_inhead;
259 int intail = x->sr_intail;
260 char *inbuf = x->sr_inbuf;
261 if (intail == inhead) return (0);
262 for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1))
264 /* if we hit a semi that isn't preceeded by a \, it's a message
265 boundary. LATER we should deal with the possibility that the
266 preceeding \ might itself be escaped! */
267 char c = *bp++ = inbuf[indx];
268 if (c == ';' && (!indx || inbuf[indx-1] != '\\'))
270 intail = (indx+1)&(INBUFSIZE-1);
271 binbuf_text(inbinbuf, messbuf, bp - messbuf);
272 if (sys_debuglevel & DEBUG_MESSDOWN)
274 write(2, messbuf, bp - messbuf);
275 write(2, "\n", 1);
277 x->sr_inhead = inhead;
278 x->sr_intail = intail;
279 return (1);
282 return (0);
285 static void socketreceiver_getudp(t_socketreceiver *x, int fd)
287 char buf[INBUFSIZE+1];
288 int ret = recv(fd, buf, INBUFSIZE, 0);
289 if (ret < 0)
291 sys_sockerror("recv");
292 sys_rmpollfn(fd);
293 sys_closesocket(fd);
295 else if (ret > 0)
297 buf[ret] = 0;
298 #if 0
299 post("%s", buf);
300 #endif
301 if (buf[ret-1] != '\n')
303 #if 0
304 buf[ret] = 0;
305 error("dropped bad buffer %s\n", buf);
306 #endif
308 else
310 char *semi = strchr(buf, ';');
311 if (semi)
312 *semi = 0;
313 binbuf_text(inbinbuf, buf, strlen(buf));
314 outlet_setstacklim();
315 if (x->sr_socketreceivefn)
316 (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
317 else bug("socketreceiver_getudp");
324 #include <termios.h>
325 #include <string.h>
327 static struct termios stored_settings;
328 EXTERN int sys_stdin;
330 void set_keypress(void)
332 struct termios new_settings;
334 tcgetattr(0,&stored_settings);
336 new_settings = stored_settings;
338 /* Disable canonical mode, and set buffer size to 1 byte */
339 new_settings.c_lflag &= (~ICANON);
340 new_settings.c_cc[VTIME] = 0;
341 new_settings.c_cc[VMIN] = 1;
343 /* echo off */
344 new_settings.c_lflag &= (~ECHO);
346 tcsetattr(0,TCSANOW,&new_settings);
347 return;
350 void reset_keypress(void)
352 if (sys_stdin)
353 tcsetattr(0,TCSANOW,&stored_settings);
354 return;
357 static t_symbol* _ss;
360 void stdin_read(t_socketreceiver *x, int fd) {
361 static char input[256];
363 char* in;
364 int got;
366 got = read(fd,input,256);
367 in = input;
368 while (got-- && _ss->s_thing)
369 pd_float(_ss->s_thing,(float)*in++);
372 void socketreceiver_read(t_socketreceiver *x, int fd)
374 if (x->sr_udp) /* UDP ("datagram") socket protocol */
375 socketreceiver_getudp(x, fd);
376 else /* TCP ("streaming") socket protocol */
378 char *semi;
379 int readto =
380 (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
381 int ret;
383 /* the input buffer might be full. If so, drop the whole thing */
384 if (readto == x->sr_inhead)
386 fprintf(stderr, "pd: dropped message from gui\n");
387 x->sr_inhead = x->sr_intail = 0;
388 readto = INBUFSIZE;
390 else
392 ret = recv(fd, x->sr_inbuf + x->sr_inhead,
393 readto - x->sr_inhead, 0);
394 if (ret < 0)
396 sys_sockerror("recv");
397 if (x == sys_socketreceiver) sys_bail(1);
398 else
400 if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
401 sys_rmpollfn(fd);
402 sys_closesocket(fd);
405 else if (ret == 0)
407 if (x == sys_socketreceiver)
409 fprintf(stderr, "pd: exiting\n");
410 sys_bail(0);
412 else
414 post("EOF on socket %d\n", fd);
415 if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
416 sys_rmpollfn(fd);
417 sys_closesocket(fd);
420 else
422 x->sr_inhead += ret;
423 if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0;
424 while (socketreceiver_doread(x))
426 outlet_setstacklim();
427 if (x->sr_socketreceivefn)
428 (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
429 else binbuf_eval(inbinbuf, 0, 0, 0);
436 void sys_closesocket(int fd)
438 #ifdef UNIX
439 close(fd);
440 #endif
441 #ifdef MSW
442 closesocket(fd);
443 #endif
447 void sys_gui(char *s)
449 int length = strlen(s), written = 0, res, histwas = sys_addhist(4);
450 if (sys_debuglevel & DEBUG_MESSUP)
451 fprintf(stderr, "%s", s);
452 if (sys_nogui)
453 return;
454 while (1)
456 res = send(sys_guisock, s + written, length, 0);
457 if (res < 0)
459 perror("pd output pipe");
460 sys_bail(1);
462 else
464 written += res;
465 if (written >= length)
466 break;
469 sys_addhist(histwas);
472 /* LATER should do a bounds check -- but how do you get printf to do that?
473 See also rtext_senditup() in this regard */
475 void sys_vgui(char *fmt, ...)
477 int result, i;
478 char buf[2048];
479 va_list ap;
481 va_start(ap, fmt);
482 vsprintf(buf, fmt, ap);
483 sys_gui(buf);
484 va_end(ap);
488 #define FIRSTPORTNUM 5400
490 /* -------------- signal handling for UNIX -------------- */
492 #ifdef UNIX
493 typedef void (*sighandler_t)(int);
495 static void sys_signal(int signo, sighandler_t sigfun)
497 struct sigaction action;
498 action.sa_flags = 0;
499 action.sa_handler = sigfun;
500 memset(&action.sa_mask, 0, sizeof(action.sa_mask));
501 #if 0 /* GG says: don't use that */
502 action.sa_restorer = 0;
503 #endif
504 if (sigaction(signo, &action, 0) < 0)
505 perror("sigaction");
508 static void sys_exithandler(int n)
510 static int trouble = 0;
511 if (!trouble)
513 trouble = 1;
514 fprintf(stderr, "Pd: signal %d\n", n);
515 sys_bail(1);
518 else _exit(1);
521 static void sys_alarmhandler(int n)
523 fprintf(stderr, "Pd: system call timed out\n");
526 static void sys_huphandler(int n)
528 struct timeval timout;
529 timout.tv_sec = 0;
530 timout.tv_usec = 30000;
531 select(1, 0, 0, 0, &timout);
534 void sys_setalarm(int microsec)
536 struct itimerval gonzo;
537 #if 0
538 fprintf(stderr, "timer %d\n", microsec);
539 #endif
540 gonzo.it_interval.tv_sec = 0;
541 gonzo.it_interval.tv_usec = 0;
542 gonzo.it_value.tv_sec = 0;
543 gonzo.it_value.tv_usec = microsec;
544 if (microsec)
545 sys_signal(SIGALRM, sys_alarmhandler);
546 else sys_signal(SIGALRM, SIG_IGN);
547 setitimer(ITIMER_REAL, &gonzo, 0);
550 #endif
552 #ifdef __linux__
554 #if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK)
555 #include <sched.h>
556 #endif
558 void sys_set_priority(int higher)
560 #ifdef _POSIX_PRIORITY_SCHEDULING
561 struct sched_param par;
562 int p1 ,p2, p3;
563 p1 = sched_get_priority_min(SCHED_FIFO);
564 p2 = sched_get_priority_max(SCHED_FIFO);
565 #ifdef USEAPI_JACK
566 p3 = (higher ? p1 + 7 : p1 + 5);
567 #else
568 p3 = (higher ? p2 - 1 : p2 - 3);
569 #endif
570 par.sched_priority = p3;
571 if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
572 fprintf(stderr, "priority %d scheduling enabled.\n", p3);
573 #endif
575 #ifdef _POSIX_MEMLOCK
576 if (mlockall(MCL_FUTURE) != -1)
577 fprintf(stderr, "memory locking enabled.\n");
578 #endif
582 #endif /* __linux__ */
584 static int sys_watchfd;
586 #ifdef __linux__
587 void glob_ping(t_pd *dummy)
589 if (write(sys_watchfd, "\n", 1) < 1)
591 fprintf(stderr, "pd: watchdog process died\n");
592 sys_bail(1);
595 #endif
597 static int defaultfontshit[] = {
598 8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28,
599 24, 15, 28};
601 int sys_startgui(const char *guidir)
603 pid_t childpid;
604 char cmdbuf[4*MAXPDSTRING];
605 struct sockaddr_in server;
606 int msgsock;
607 char buf[15];
608 int len = sizeof(server);
609 int ntry = 0, portno = FIRSTPORTNUM;
610 int xsock = -1;
611 #ifdef MSW
612 short version = MAKEWORD(2, 0);
613 WSADATA nobby;
614 #endif
615 #ifdef UNIX
616 int stdinpipe[2];
617 #endif
618 /* create an empty FD poll list */
619 sys_fdpoll = (t_fdpoll *)t_getbytes(0);
620 sys_nfdpoll = 0;
621 inbinbuf = binbuf_new();
623 #ifdef UNIX
624 signal(SIGHUP, sys_huphandler);
625 signal(SIGINT, sys_exithandler);
626 signal(SIGQUIT, sys_exithandler);
627 signal(SIGILL, sys_exithandler);
628 signal(SIGIOT, sys_exithandler);
629 signal(SIGFPE, SIG_IGN);
630 /* signal(SIGILL, sys_exithandler);
631 signal(SIGBUS, sys_exithandler);
632 signal(SIGSEGV, sys_exithandler); */
633 signal(SIGPIPE, SIG_IGN);
634 signal(SIGALRM, SIG_IGN);
635 signal(SIGTERM, SIG_IGN);
636 #if 0 /* GG says: don't use that */
637 signal(SIGSTKFLT, sys_exithandler);
638 #endif
639 #endif
640 #ifdef MSW
641 if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
642 #endif
644 if (sys_nogui)
646 /* fake the GUI's message giving cwd and font sizes; then
647 skip starting the GUI up. */
648 t_atom zz[19];
649 int i;
650 #ifdef MSW
651 if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0)
652 strcpy(cmdbuf, ".");
653 #endif
654 #ifdef UNIX
655 if (!getcwd(cmdbuf, MAXPDSTRING))
656 strcpy(cmdbuf, ".");
658 #endif
659 SETSYMBOL(zz, gensym(cmdbuf));
660 for (i = 1; i < 22; i++)
661 SETFLOAT(zz + i, defaultfontshit[i-1]);
662 SETFLOAT(zz+22,0);
663 glob_initfromgui(0, 0, 23, zz);
665 else
667 #ifdef MSW
668 char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80];
669 int spawnret;
671 #endif
672 #ifdef MSW
673 char intarg;
674 #else
675 int intarg;
676 #endif
678 /* create a socket */
679 xsock = socket(AF_INET, SOCK_STREAM, 0);
680 if (xsock < 0) sys_sockerror("socket");
681 #if 0
682 intarg = 0;
683 if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF,
684 &intarg, sizeof(intarg)) < 0)
685 post("setsockopt (SO_RCVBUF) failed\n");
686 intarg = 0;
687 if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF,
688 &intarg, sizeof(intarg)) < 0)
689 post("setsockopt (SO_RCVBUF) failed\n");
690 #endif
691 intarg = 1;
692 if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY,
693 &intarg, sizeof(intarg)) < 0)
694 #ifndef MSW
695 post("setsockopt (TCP_NODELAY) failed\n")
696 #endif
700 server.sin_family = AF_INET;
701 server.sin_addr.s_addr = INADDR_ANY;
703 /* assign server port number */
704 server.sin_port = htons((unsigned short)portno);
706 /* name the socket */
707 while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0)
709 #ifdef MSW
710 int err = WSAGetLastError();
711 #endif
712 #ifdef UNIX
713 int err = errno;
714 #endif
715 if ((ntry++ > 20) || (err != EADDRINUSE))
717 perror("bind");
718 fprintf(stderr,
719 "Pd needs your machine to be configured with\n");
720 fprintf(stderr,
721 "'networking' turned on (see Pd's html doc for details.)\n");
722 exit(1);
724 portno++;
725 server.sin_port = htons((unsigned short)(portno));
728 if (sys_verbose) fprintf(stderr, "port %d\n", portno);
730 sys_socketreceiver = socketreceiver_new(0, 0, 0, 0);
732 #ifdef UNIX
733 childpid = fork();
734 if (childpid < 0)
736 if (errno) perror("sys_startgui");
737 else fprintf(stderr, "sys_startgui failed\n");
738 return (1);
740 else if (!childpid) /* we're the child */
742 seteuid(getuid()); /* lose setuid priveliges */
743 #ifndef MACOSX
744 /* the wish process in Unix will make a wish shell and
745 read/write standard in and out unless we close the
746 file descriptors. Somehow this doesn't make the MAC OSX
747 version of Wish happy...*/
748 if (pipe(stdinpipe) < 0)
749 sys_sockerror("pipe");
750 else
752 if (stdinpipe[0] != 0)
754 close (0);
755 dup2(stdinpipe[0], 0);
756 close(stdinpipe[0]);
759 #endif
760 if (!sys_guicmd)
762 #ifdef MACOSX
763 char *homedir = getenv("HOME"), filename[250];
764 struct stat statbuf;
765 if (!homedir || strlen(homedir) > 150)
766 goto nohomedir;
767 sprintf(filename,
768 "%s/Applications/Utilities/Wish shell.app/Contents/MacOS/Wish Shell",
769 homedir);
770 if (stat(filename, &statbuf) >= 0)
771 goto foundit;
772 sprintf(filename,
773 "%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell",
774 homedir);
775 if (stat(filename, &statbuf) >= 0)
776 goto foundit;
777 nohomedir:
778 strcpy(filename,
779 "/Applications/Utilities/Wish Shell.app/Contents/MacOS/Wish Shell");
780 if (stat(filename, &statbuf) >= 0)
781 goto foundit;
782 strcpy(filename,
783 "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell");
784 foundit:
785 sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno);
786 #else
787 sprintf(cmdbuf,
788 "TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \
789 \"%s/pd-gui\" %d\n",
790 sys_libdir->s_name, sys_libdir->s_name, guidir, portno);
791 #endif
792 sys_guicmd = cmdbuf;
794 if (sys_verbose) fprintf(stderr, "%s", sys_guicmd);
795 execl("/bin/sh", "sh", "-c", sys_guicmd, 0);
796 perror("pd: exec");
797 _exit(1);
799 #endif /* UNIX */
801 #ifdef MSW
802 /* in MSW land "guipath" is unused; we just do everything from
803 the libdir. */
804 /* fprintf(stderr, "%s\n", sys_libdir->s_name); */
806 strcpy(scriptbuf, "\"");
807 strcat(scriptbuf, sys_libdir->s_name);
808 strcat(scriptbuf, "/" PDBINDIR "pd.tk\"");
809 sys_bashfilename(scriptbuf, scriptbuf);
811 sprintf(portbuf, "%d", portno);
813 strcpy(wishbuf, sys_libdir->s_name);
814 strcat(wishbuf, "/" PDBINDIR WISHAPP);
815 sys_bashfilename(wishbuf, wishbuf);
817 spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0);
818 if (spawnret < 0)
820 perror("spawnl");
821 fprintf(stderr, "%s: couldn't load TCL\n", wishbuf);
822 exit(1);
825 #endif /* MSW */
828 #ifdef __linux__
829 /* now that we've spun off the child process we can promote
830 our process's priority, if we happen to be root. */
831 if (sys_hipriority)
833 if (!getuid() || !geteuid())
835 /* To prevent lockup, we fork off a watchdog process with
836 higher real-time priority than ours. The GUI has to send
837 a stream of ping messages to the watchdog THROUGH the Pd
838 process which has to pick them up from the GUI and forward
839 them. If any of these things aren't happening the watchdog
840 starts sending "stop" and "cont" signals to the Pd process
841 to make it timeshare with the rest of the system. (Version
842 0.33P2 : if there's no GUI, the watchdog pinging is done
843 from the scheduler idle routine in this process instead.) */
845 int pipe9[2], watchpid;
846 if (pipe(pipe9) < 0)
848 seteuid(getuid()); /* lose setuid priveliges */
849 sys_sockerror("pipe");
850 return (1);
852 watchpid = fork();
853 if (watchpid < 0)
855 seteuid(getuid()); /* lose setuid priveliges */
856 if (errno)
857 perror("sys_startgui");
858 else fprintf(stderr, "sys_startgui failed\n");
859 return (1);
861 else if (!watchpid) /* we're the child */
863 sys_set_priority(1);
864 seteuid(getuid()); /* lose setuid priveliges */
865 if (pipe9[1] != 0)
867 dup2(pipe9[0], 0);
868 close(pipe9[0]);
870 close(pipe9[1]);
872 sprintf(cmdbuf, "%s/pd-watchdog\n", guidir);
873 if (sys_verbose) fprintf(stderr, "%s", cmdbuf);
874 execl("/bin/sh", "sh", "-c", cmdbuf, 0);
875 perror("pd: exec");
876 _exit(1);
878 else /* we're the parent */
880 sys_set_priority(0);
881 seteuid(getuid()); /* lose setuid priveliges */
882 close(pipe9[0]);
883 sys_watchfd = pipe9[1];
884 /* We also have to start the ping loop in the GUI;
885 this is done later when the socket is open. */
888 else
890 post("realtime setting failed because not root\n");
891 sys_hipriority = 0;
895 seteuid(getuid()); /* lose setuid priveliges */
896 #endif /* __linux__ */
898 #ifdef MSW
899 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
900 fprintf(stderr, "pd: couldn't set high priority class\n");
901 #endif
902 #ifdef MACOSX
903 if (sys_hipriority)
905 struct sched_param param;
906 int policy = SCHED_RR;
907 int err;
908 param.sched_priority = 80; // adjust 0 : 100
910 err = pthread_setschedparam(pthread_self(), policy, &param);
911 if (err)
912 post("warning: high priority scheduling failed\n");
914 #endif /* MACOSX */
916 if (!sys_nogui)
918 char buf[256];
919 if (sys_verbose)
920 fprintf(stderr, "Waiting for connection request... \n");
921 if (listen(xsock, 5) < 0) sys_sockerror("listen");
923 sys_guisock = accept(xsock, (struct sockaddr *) &server, &len);
924 #ifdef OOPS
925 close(xsock);
926 #endif
927 if (sys_guisock < 0) sys_sockerror("accept");
928 sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read,
929 sys_socketreceiver);
931 if (sys_verbose)
932 fprintf(stderr, "... connected\n");
934 /* here is where we start the pinging. */
935 #ifdef __linux__
936 if (sys_hipriority)
937 sys_gui("pdtk_watchdog\n");
938 #endif
939 sys_get_audio_apis(buf);
940 sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf);
942 if (sys_stdin) {
943 set_keypress();
944 _ss = gensym("stdin");
945 sys_addpollfn(1, (t_fdpollfn) stdin_read,NULL);
947 return (0);
952 static int sys_poll_togui(void)
954 /* LATER use this to flush output buffer to gui */
955 return (0);
958 int sys_pollgui(void)
960 return (sys_domicrosleep(0, 1) || sys_poll_togui());
964 /* T.Grill - import clean quit function */
965 extern void sys_exit(void);
967 /* This is called when something bad has happened, like a segfault.
968 Call glob_quit() below to exit cleanly.
969 LATER try to save dirty documents even in the bad case. */
970 void sys_bail(int n)
972 static int reentered = 0;
973 reset_keypress();
974 if (!reentered)
976 reentered = 1;
977 #ifndef __linux /* sys_close_audio() hangs if you're in a signal? */
978 fprintf(stderr, "closing audio...\n");
979 sys_close_audio();
980 fprintf(stderr, "closing MIDI...\n");
981 sys_close_midi();
982 fprintf(stderr, "... done.\n");
983 #endif
984 exit(1);
986 else _exit(n);
989 void glob_quit(void *dummy)
991 sys_vgui("exit\n");
992 if (!sys_nogui)
994 close(sys_guisock);
995 sys_rmpollfn(sys_guisock);
997 reset_keypress();
998 sys_bail(0);