diff options
Diffstat (limited to 'pd/src/s_inter.c')
-rw-r--r-- | pd/src/s_inter.c | 1301 |
1 files changed, 793 insertions, 508 deletions
diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c index cd6096bb..05232d59 100644 --- a/pd/src/s_inter.c +++ b/pd/src/s_inter.c @@ -8,7 +8,8 @@ that didn't really belong anywhere. */ #include "m_pd.h" #include "s_stuff.h" #include "m_imp.h" -#ifdef UNIX +#include "g_canvas.h" /* for GUI queueing stuff */ +#ifndef MSW #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> @@ -44,7 +45,7 @@ typedef int pid_t; #include <stdlib.h> #endif -#define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */ +#define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */ #define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */ /* T.Grill - make it a _little_ more adaptable... */ @@ -53,10 +54,14 @@ typedef int pid_t; #endif #ifndef WISHAPP -#define WISHAPP "wish83.exe" +#define WISHAPP "wish84.exe" #endif -extern char pd_version[]; +#ifdef __linux__ +#define LOCALHOST "127.0.0.1" +#else +#define LOCALHOST "localhost" +#endif typedef struct _fdpoll { @@ -78,6 +83,9 @@ struct _socketreceiver t_socketreceivefn sr_socketreceivefn; }; +extern char pd_version[]; +extern int sys_guisetportnumber; + static int sys_nfdpoll; static t_fdpoll *sys_fdpoll; static int sys_maxfd; @@ -87,6 +95,8 @@ static t_binbuf *inbinbuf; static t_socketreceiver *sys_socketreceiver; extern int sys_addhist(int phase); +/* ----------- functions for timing, signals, priorities, etc --------- */ + #ifdef MSW static LARGE_INTEGER nt_inittime; static double nt_freq = 0; @@ -120,17 +130,16 @@ double nt_tixtotime(LARGE_INTEGER *dumbass) /* get "real time" in seconds; take the first time we get called as a reference time of zero. */ -double sys_getrealtime(void) +double sys_getrealtime(void) { -#ifdef UNIX +#ifndef MSW static struct timeval then; struct timeval now; gettimeofday(&now, 0); if (then.tv_sec == 0 && then.tv_usec == 0) then = now; return ((now.tv_sec - then.tv_sec) + - (1./1000000.) * (now.tv_usec - then.tv_usec)); -#endif -#ifdef MSW + (1./1000000.) * (now.tv_usec - then.tv_usec)); +#else LARGE_INTEGER now; QueryPerformanceCounter(&now); if (nt_freq == 0) sys_initntclock(); @@ -138,6 +147,164 @@ double sys_getrealtime(void) #endif } +static int sys_domicrosleep(int microsec, int pollem) +{ + struct timeval timout; + int i, didsomething = 0; + t_fdpoll *fp; + timout.tv_sec = 0; + timout.tv_usec = microsec; + if (pollem) + { + fd_set readset, writeset, exceptset; + FD_ZERO(&writeset); + FD_ZERO(&readset); + FD_ZERO(&exceptset); + for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++) + FD_SET(fp->fdp_fd, &readset); + select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout); + for (i = 0; i < sys_nfdpoll; i++) + if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset)) + { + (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd); + didsomething = 1; + } + return (didsomething); + } + else + { + select(0, 0, 0, 0, &timout); + return (0); + } +} + +void sys_microsleep(int microsec) +{ + sys_domicrosleep(microsec, 1); +} + +#ifdef UNISTD +typedef void (*sighandler_t)(int); + +static void sys_signal(int signo, sighandler_t sigfun) +{ + struct sigaction action; + action.sa_flags = 0; + action.sa_handler = sigfun; + memset(&action.sa_mask, 0, sizeof(action.sa_mask)); +#if 0 /* GG says: don't use that */ + action.sa_restorer = 0; +#endif + if (sigaction(signo, &action, 0) < 0) + perror("sigaction"); +} + +static void sys_exithandler(int n) +{ + static int trouble = 0; + if (!trouble) + { + trouble = 1; + fprintf(stderr, "Pd: signal %d\n", n); + sys_bail(1); + } + else _exit(1); +} + +static void sys_alarmhandler(int n) +{ + fprintf(stderr, "Pd: system call timed out\n"); +} + +static void sys_huphandler(int n) +{ + struct timeval timout; + timout.tv_sec = 0; + timout.tv_usec = 30000; + select(1, 0, 0, 0, &timout); +} + +void sys_setalarm(int microsec) +{ + struct itimerval gonzo; +#if 0 + fprintf(stderr, "timer %d\n", microsec); +#endif + gonzo.it_interval.tv_sec = 0; + gonzo.it_interval.tv_usec = 0; + gonzo.it_value.tv_sec = 0; + gonzo.it_value.tv_usec = microsec; + if (microsec) + sys_signal(SIGALRM, sys_alarmhandler); + else sys_signal(SIGALRM, SIG_IGN); + setitimer(ITIMER_REAL, &gonzo, 0); +} + +#endif + +#ifdef __linux + +#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK) +#include <sched.h> +#endif + +void sys_set_priority(int higher) +{ +#ifdef _POSIX_PRIORITY_SCHEDULING + struct sched_param par; + int p1 ,p2, p3; + p1 = sched_get_priority_min(SCHED_FIFO); + p2 = sched_get_priority_max(SCHED_FIFO); +#ifdef USEAPI_JACK + p3 = (higher ? p1 + 7 : p1 + 5); +#else + p3 = (higher ? p2 - 1 : p2 - 3); +#endif + par.sched_priority = p3; + if (sched_setscheduler(0,SCHED_FIFO,&par) != -1) + fprintf(stderr, "priority %d scheduling enabled.\n", p3); +#endif + +#ifdef _POSIX_MEMLOCK + if (mlockall(MCL_FUTURE) != -1) + fprintf(stderr, "memory locking enabled.\n"); +#endif + +} + +#endif /* __linux__ */ + +#ifdef IRIX /* hack by <olaf.matthes@gmx.de> at 2003/09/21 */ + +#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK) +#include <sched.h> +#endif + +void sys_set_priority(int higher) +{ +#ifdef _POSIX_PRIORITY_SCHEDULING + struct sched_param par; + /* Bearing the table found in 'man realtime' in mind, I found it a */ + /* good idea to use 192 as the priority setting for Pd. Any thoughts? */ + if (higher) + par.sched_priority = 250; /* priority for watchdog */ + else + par.sched_priority = 192; /* priority for pd (DSP) */ + + if (sched_setscheduler(0, SCHED_FIFO, &par) != -1) + fprintf(stderr, "priority %d scheduling enabled.\n", par.sched_priority); +#endif + +#ifdef _POSIX_MEMLOCK + if (mlockall(MCL_FUTURE) != -1) + fprintf(stderr, "memory locking enabled.\n"); +#endif +} +/* end of hack */ +#endif /* IRIX */ + +/* ------------------ receiving incoming messages over sockets ------------- */ + void sys_sockerror(char *s) { #ifdef MSW @@ -145,12 +312,11 @@ void sys_sockerror(char *s) if (err == 10054) return; else if (err == 10044) { - fprintf(stderr, - "Warning: you might not have TCP/IP \"networking\" turned on\n"); - fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n"); + fprintf(stderr, + "Warning: you might not have TCP/IP \"networking\" turned on\n"); + fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n"); } -#endif -#ifdef UNIX +#else int err = errno; #endif fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err); @@ -162,7 +328,7 @@ void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr) int size = nfd * sizeof(t_fdpoll); t_fdpoll *fp; sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, - size + sizeof(t_fdpoll)); + size + sizeof(t_fdpoll)); fp = sys_fdpoll + nfd; fp->fdp_fd = fd; fp->fdp_fn = fn; @@ -178,58 +344,22 @@ void sys_rmpollfn(int fd) t_fdpoll *fp; for (i = nfd, fp = sys_fdpoll; i--; fp++) { - if (fp->fdp_fd == fd) - { - while (i--) - { - fp[0] = fp[1]; - fp++; - } - sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, - size - sizeof(t_fdpoll)); - sys_nfdpoll = nfd - 1; - return; - } + if (fp->fdp_fd == fd) + { + while (i--) + { + fp[0] = fp[1]; + fp++; + } + sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, + size - sizeof(t_fdpoll)); + sys_nfdpoll = nfd - 1; + return; + } } post("warning: %d removed from poll list but not found", fd); } -static int sys_domicrosleep(int microsec, int pollem) -{ - struct timeval timout; - int i, didsomething = 0; - t_fdpoll *fp; - timout.tv_sec = 0; - timout.tv_usec = microsec; - if (pollem) - { - fd_set readset, writeset, exceptset; - FD_ZERO(&writeset); - FD_ZERO(&readset); - FD_ZERO(&exceptset); - for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++) - FD_SET(fp->fdp_fd, &readset); - select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout); - for (i = 0; i < sys_nfdpoll; i++) - if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset)) - { - (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd); - didsomething = 1; - } - return (didsomething); - } - else - { - select(0, 0, 0, 0, &timout); - return (0); - } -} - -void sys_microsleep(int microsec) -{ - sys_domicrosleep(microsec, 1); -} - t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp) { @@ -261,23 +391,23 @@ static int socketreceiver_doread(t_socketreceiver *x) if (intail == inhead) return (0); for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) { - /* if we hit a semi that isn't preceeded by a \, it's a message - boundary. LATER we should deal with the possibility that the - preceeding \ might itself be escaped! */ - char c = *bp++ = inbuf[indx]; - if (c == ';' && (!indx || inbuf[indx-1] != '\\')) - { - intail = (indx+1)&(INBUFSIZE-1); - binbuf_text(inbinbuf, messbuf, bp - messbuf); - if (sys_debuglevel & DEBUG_MESSDOWN) - { - write(2, messbuf, bp - messbuf); - write(2, "\n", 1); - } - x->sr_inhead = inhead; - x->sr_intail = intail; - return (1); - } + /* if we hit a semi that isn't preceeded by a \, it's a message + boundary. LATER we should deal with the possibility that the + preceeding \ might itself be escaped! */ + char c = *bp++ = inbuf[indx]; + if (c == ';' && (!indx || inbuf[indx-1] != '\\')) + { + intail = (indx+1)&(INBUFSIZE-1); + binbuf_text(inbinbuf, messbuf, bp - messbuf); + if (sys_debuglevel & DEBUG_MESSDOWN) + { + write(2, messbuf, bp - messbuf); + write(2, "\n", 1); + } + x->sr_inhead = inhead; + x->sr_intail = intail; + return (1); + } } return (0); } @@ -288,104 +418,104 @@ static void socketreceiver_getudp(t_socketreceiver *x, int fd) int ret = recv(fd, buf, INBUFSIZE, 0); if (ret < 0) { - sys_sockerror("recv"); - sys_rmpollfn(fd); - sys_closesocket(fd); + sys_sockerror("recv"); + sys_rmpollfn(fd); + sys_closesocket(fd); } else if (ret > 0) { - buf[ret] = 0; + buf[ret] = 0; #if 0 - post("%s", buf); + post("%s", buf); #endif - if (buf[ret-1] != '\n') - { + if (buf[ret-1] != '\n') + { #if 0 - buf[ret] = 0; - error("dropped bad buffer %s\n", buf); -#endif - } - else - { - char *semi = strchr(buf, ';'); - if (semi) - *semi = 0; - binbuf_text(inbinbuf, buf, strlen(buf)); - outlet_setstacklim(); - if (x->sr_socketreceivefn) - (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); - else bug("socketreceiver_getudp"); - } + buf[ret] = 0; + error("dropped bad buffer %s\n", buf); +#endif + } + else + { + char *semi = strchr(buf, ';'); + if (semi) + *semi = 0; + binbuf_text(inbinbuf, buf, strlen(buf)); + outlet_setstacklim(); + if (x->sr_socketreceivefn) + (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); + else bug("socketreceiver_getudp"); + } } } void socketreceiver_read(t_socketreceiver *x, int fd) { if (x->sr_udp) /* UDP ("datagram") socket protocol */ - socketreceiver_getudp(x, fd); + socketreceiver_getudp(x, fd); else /* TCP ("streaming") socket protocol */ { - char *semi; - int readto = - (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); - int ret; - - /* the input buffer might be full. If so, drop the whole thing */ - if (readto == x->sr_inhead) - { - fprintf(stderr, "pd: dropped message from gui\n"); - x->sr_inhead = x->sr_intail = 0; - readto = INBUFSIZE; - } - else - { - ret = recv(fd, x->sr_inbuf + x->sr_inhead, - readto - x->sr_inhead, 0); - if (ret < 0) - { - sys_sockerror("recv"); - if (x == sys_socketreceiver) sys_bail(1); - else - { - if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); - sys_rmpollfn(fd); - sys_closesocket(fd); - } - } - else if (ret == 0) - { - if (x == sys_socketreceiver) - { - fprintf(stderr, "pd: exiting\n"); - sys_bail(0); - } - else - { - post("EOF on socket %d\n", fd); - if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); - sys_rmpollfn(fd); - sys_closesocket(fd); - } - } - else - { - x->sr_inhead += ret; - if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; - while (socketreceiver_doread(x)) - { - outlet_setstacklim(); - if (x->sr_socketreceivefn) - (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); - else binbuf_eval(inbinbuf, 0, 0, 0); - } - } - } + char *semi; + int readto = + (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); + int ret; + + /* the input buffer might be full. If so, drop the whole thing */ + if (readto == x->sr_inhead) + { + fprintf(stderr, "pd: dropped message from gui\n"); + x->sr_inhead = x->sr_intail = 0; + readto = INBUFSIZE; + } + else + { + ret = recv(fd, x->sr_inbuf + x->sr_inhead, + readto - x->sr_inhead, 0); + if (ret < 0) + { + sys_sockerror("recv"); + if (x == sys_socketreceiver) sys_bail(1); + else + { + if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); + sys_rmpollfn(fd); + sys_closesocket(fd); + } + } + else if (ret == 0) + { + if (x == sys_socketreceiver) + { + fprintf(stderr, "pd: exiting\n"); + sys_bail(0); + } + else + { + post("EOF on socket %d\n", fd); + if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); + sys_rmpollfn(fd); + sys_closesocket(fd); + } + } + else + { + x->sr_inhead += ret; + if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; + while (socketreceiver_doread(x)) + { + outlet_setstacklim(); + if (x->sr_socketreceivefn) + (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); + else binbuf_eval(inbinbuf, 0, 0, 0); + } + } + } } } void sys_closesocket(int fd) { -#ifdef UNIX +#ifdef UNISTD close(fd); #endif #ifdef MSW @@ -393,156 +523,290 @@ void sys_closesocket(int fd) #endif } +/* ---------------------- sending messages to the GUI ------------------ */ +#define GUI_ALLOCCHUNK 8192 +#define GUI_UPDATESLICE 512 /* how much we try to do in one idle period */ +#define GUI_BYTESPERPING 1024 /* how much we send up per ping */ -void sys_gui(char *s) +typedef struct _guiqueue { - int length = strlen(s), written = 0, res, histwas = sys_addhist(4); - if (sys_debuglevel & DEBUG_MESSUP) - fprintf(stderr, "%s", s); - if (sys_nogui) - return; - while (1) + void *gq_client; + t_glist *gq_glist; + t_guicallbackfn gq_fn; + struct _guiqueue *gq_next; +} t_guiqueue; + +static t_guiqueue *sys_guiqueuehead; +static char *sys_guibuf; +static int sys_guibufhead; +static int sys_guibuftail; +static int sys_guibufsize; +static int sys_waitingforping; +static int sys_bytessincelastping; + +static void sys_trytogetmoreguibuf(int newsize) +{ + char *newbuf = realloc(sys_guibuf, newsize); +#if 0 + static int sizewas; + if (newsize > 70000 && sizewas < 70000) { - res = send(sys_guisock, s + written, length, 0); - if (res < 0) - { - perror("pd output pipe"); - sys_bail(1); - } - else - { - written += res; - if (written >= length) - break; - } + int i; + for (i = sys_guibuftail; i < sys_guibufhead; i++) + fputc(sys_guibuf[i], stderr); } - sys_addhist(histwas); -} + sizewas = newsize; +#endif +#if 0 + fprintf(stderr, "new size %d (head %d, tail %d)\n", + newsize, sys_guibufhead, sys_guibuftail); +#endif -/* LATER should do a bounds check -- but how do you get printf to do that? - See also rtext_senditup() in this regard */ + /* if realloc fails, make a last-ditch attempt to stay alive by + synchronously writing out the existing contents. LATER test + this by intentionally setting newbuf to zero */ + if (!newbuf) + { + int bytestowrite = sys_guibuftail - sys_guibufhead; + int written = 0; + while (1) + { + int res = send(sys_guisock, + sys_guibuf + sys_guibuftail + written, bytestowrite, 0); + if (res < 0) + { + perror("pd output pipe"); + sys_bail(1); + } + else + { + written += res; + if (written >= bytestowrite) + break; + } + } + sys_guibufhead = sys_guibuftail = 0; + } + else + { + sys_guibufsize = newsize; + sys_guibuf = newbuf; + } +} void sys_vgui(char *fmt, ...) { - int result, i; - char buf[2048]; + int msglen, bytesleft, headwas, nwrote; va_list ap; + if (sys_nogui) + return; + if (!sys_guibuf) + { + if (!(sys_guibuf = malloc(GUI_ALLOCCHUNK))) + { + fprintf(stderr, "Pd: couldn't allocate GUI buffer\n"); + sys_bail(1); + } + sys_guibufsize = GUI_ALLOCCHUNK; + sys_guibufhead = sys_guibuftail = 0; + } + if (sys_guibufhead > sys_guibufsize - 50) + sys_trytogetmoreguibuf(sys_guibufsize + GUI_ALLOCCHUNK); va_start(ap, fmt); - vsprintf(buf, fmt, ap); - sys_gui(buf); + msglen = vsnprintf(sys_guibuf + sys_guibufhead, + sys_guibufsize - sys_guibufhead, fmt, ap); va_end(ap); + if (msglen >= sys_guibufsize - sys_guibufhead) + { + int newsize = sys_guibufsize + 1 + + (msglen > GUI_ALLOCCHUNK ? msglen : GUI_ALLOCCHUNK); + sys_trytogetmoreguibuf(newsize); + + va_start(ap, fmt); + msglen = vsnprintf(sys_guibuf + sys_guibufhead, + sys_guibufsize + 1 - sys_guibufhead, fmt, ap); + va_end(ap); + if (msglen >= sys_guibufsize - sys_guibufhead) + msglen = sys_guibufsize - sys_guibufhead - 1; + } + if (sys_debuglevel & DEBUG_MESSUP) + fprintf(stderr, "%s", sys_guibuf + sys_guibufhead); + sys_guibufhead += msglen; + sys_bytessincelastping += msglen; } +void sys_gui(char *s) +{ + sys_vgui("%s", s); +} -#define FIRSTPORTNUM 5400 +static int sys_flushtogui( void) +{ + int writesize = sys_guibufhead - sys_guibuftail, nwrote = 0; + if (writesize > 0) + nwrote = send(sys_guisock, sys_guibuf + sys_guibuftail, writesize, 0); -/* -------------- signal handling for UNIX -------------- */ +#if 0 + if (writesize) + fprintf(stderr, "wrote %d of %d\n", nwrote, writesize); +#endif -#ifdef UNIX -typedef void (*sighandler_t)(int); + if (nwrote < 0) + { + perror("pd-to-gui socket"); + sys_bail(1); + } + else if (!nwrote) + return (0); + else if (nwrote >= sys_guibufhead - sys_guibuftail) + sys_guibufhead = sys_guibuftail = 0; + else if (nwrote) + { + sys_guibuftail += nwrote; + if (sys_guibuftail > (sys_guibufsize >> 2)) + { + memmove(sys_guibuf, sys_guibuf + sys_guibuftail, + sys_guibufhead - sys_guibuftail); + sys_guibufhead = sys_guibufhead - sys_guibuftail; + sys_guibuftail = 0; + } + } + return (1); +} -static void sys_signal(int signo, sighandler_t sigfun) +void glob_ping(t_pd *dummy) { - struct sigaction action; - action.sa_flags = 0; - action.sa_handler = sigfun; - memset(&action.sa_mask, 0, sizeof(action.sa_mask)); -#if 0 /* GG says: don't use that */ - action.sa_restorer = 0; -#endif - if (sigaction(signo, &action, 0) < 0) - perror("sigaction"); + sys_waitingforping = 0; } -static void sys_exithandler(int n) +static int sys_flushqueue(void ) { - static int trouble = 0; - if (!trouble) + int wherestop = sys_bytessincelastping + GUI_UPDATESLICE; + if (wherestop + (GUI_UPDATESLICE >> 1) > GUI_BYTESPERPING) + wherestop = 0x7fffffff; + if (sys_waitingforping) + return (0); + if (!sys_guiqueuehead) + return (0); + while (1) { - trouble = 1; - fprintf(stderr, "Pd: signal %d\n", n); - sys_bail(1); - + if (sys_bytessincelastping >= GUI_BYTESPERPING) + { + sys_gui("pdtk_ping\n"); + sys_bytessincelastping = 0; + sys_waitingforping = 1; + return (1); + } + if (sys_guiqueuehead) + { + t_guiqueue *headwas = sys_guiqueuehead; + sys_guiqueuehead = headwas->gq_next; + (*headwas->gq_fn)(headwas->gq_client, headwas->gq_glist); + t_freebytes(headwas, sizeof(*headwas)); + if (sys_bytessincelastping >= wherestop) + break; + } + else break; } - else _exit(1); + sys_flushtogui(); + return (1); } -static void sys_alarmhandler(int n) + /* flush output buffer and update queue to gui in small time slices */ +static int sys_poll_togui(void) /* returns 1 if did anything */ { - fprintf(stderr, "Pd: system call timed out\n"); + if (sys_nogui) + return (0); + /* see if there is stuff still in the buffer, if so we + must have fallen behind, so just try to clear that. */ + if (sys_flushtogui()) + return (1); + /* if the flush wasn't complete, wait. */ + if (sys_guibufhead > sys_guibuftail) + return (0); + + /* check for queued updates */ + if (sys_flushqueue()) + return (1); + + return (0); } -static void sys_huphandler(int n) + /* if some GUI object is having to do heavy computations, it can tell + us to back off from doing more updates by faking a big one itself. */ +void sys_pretendguibytes(int n) { - struct timeval timout; - timout.tv_sec = 0; - timout.tv_usec = 30000; - select(1, 0, 0, 0, &timout); + sys_bytessincelastping += n; } -void sys_setalarm(int microsec) +void sys_queuegui(void *client, t_glist *glist, t_guicallbackfn f) { - struct itimerval gonzo; -#if 0 - fprintf(stderr, "timer %d\n", microsec); -#endif - gonzo.it_interval.tv_sec = 0; - gonzo.it_interval.tv_usec = 0; - gonzo.it_value.tv_sec = 0; - gonzo.it_value.tv_usec = microsec; - if (microsec) - sys_signal(SIGALRM, sys_alarmhandler); - else sys_signal(SIGALRM, SIG_IGN); - setitimer(ITIMER_REAL, &gonzo, 0); + t_guiqueue **gqnextptr, *gq; + if (!sys_guiqueuehead) + gqnextptr = &sys_guiqueuehead; + else + { + for (gq = sys_guiqueuehead; gq->gq_next; gq = gq->gq_next) + if (gq->gq_client == client) + return; + gqnextptr = &gq->gq_next; + } + gq = t_getbytes(sizeof(*gq)); + gq->gq_next = 0; + gq->gq_client = client; + gq->gq_glist = glist; + gq->gq_fn = f; + gq->gq_next = 0; + *gqnextptr = gq; } -#endif - -#ifdef __linux - -#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK) -#include <sched.h> -#endif +void sys_unqueuegui(void *client) +{ + t_guiqueue *gq, *gq2; + if (!sys_guiqueuehead) + return; + if (sys_guiqueuehead->gq_client == client) + { + t_freebytes(sys_guiqueuehead, sizeof(*sys_guiqueuehead)); + sys_guiqueuehead = 0; + } + else for (gq = sys_guiqueuehead; gq2 = gq->gq_next; gq = gq2) + if (gq2->gq_client == client) + { + gq->gq_next = gq2->gq_next; + t_freebytes(gq, sizeof(*gq)); + break; + } +} -void sys_set_priority(int higher) +int sys_pollgui(void) { -#ifdef _POSIX_PRIORITY_SCHEDULING - struct sched_param par; - int p1 ,p2, p3; - p1 = sched_get_priority_min(SCHED_FIFO); - p2 = sched_get_priority_max(SCHED_FIFO); - p3 = (higher ? p2 - 1 : p2 - 3); - par.sched_priority = p3; - if (sched_setscheduler(0,SCHED_FIFO,&par) != -1) - fprintf(stderr, "priority %d scheduling enabled.\n", p3); -#endif + return (sys_domicrosleep(0, 1) || sys_poll_togui()); +} -#ifdef _POSIX_MEMLOCK - if (mlockall(MCL_FUTURE) != -1) - fprintf(stderr, "memory locking enabled.\n"); -#endif -} -#endif /* __linux */ +/* --------------------- starting up the GUI connection ------------- */ static int sys_watchfd; #ifdef __linux__ -void glob_ping(t_pd *dummy) +void glob_watchdog(t_pd *dummy) { if (write(sys_watchfd, "\n", 1) < 1) { - fprintf(stderr, "pd: watchdog process died\n"); - sys_bail(1); + fprintf(stderr, "pd: watchdog process died\n"); + sys_bail(1); } } #endif +#define FIRSTPORTNUM 5400 + static int defaultfontshit[] = { 8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28, - 24, 15, 28}; + 24, 15, 28}; int sys_startgui(const char *guidir) { @@ -558,15 +822,16 @@ int sys_startgui(const char *guidir) short version = MAKEWORD(2, 0); WSADATA nobby; #endif -#ifdef UNIX +#ifdef UNISTD int stdinpipe[2]; #endif + /* create an empty FD poll list */ sys_fdpoll = (t_fdpoll *)t_getbytes(0); sys_nfdpoll = 0; inbinbuf = binbuf_new(); -#ifdef UNIX +#ifdef UNISTD signal(SIGHUP, sys_huphandler); signal(SIGINT, sys_exithandler); signal(SIGQUIT, sys_exithandler); @@ -576,9 +841,8 @@ int sys_startgui(const char *guidir) /* signal(SIGILL, sys_exithandler); signal(SIGBUS, sys_exithandler); signal(SIGSEGV, sys_exithandler); */ - signal(SIGPIPE, sys_exithandler); + signal(SIGPIPE, SIG_IGN); signal(SIGALRM, SIG_IGN); - signal(SIGTERM, SIG_IGN); #if 0 /* GG says: don't use that */ signal(SIGSTKFLT, sys_exithandler); #endif @@ -589,122 +853,153 @@ int sys_startgui(const char *guidir) if (sys_nogui) { - /* fake the GUI's message giving cwd and font sizes; then - skip starting the GUI up. */ - t_atom zz[19]; - int i; + /* fake the GUI's message giving cwd and font sizes; then + skip starting the GUI up. */ + t_atom zz[19]; + int i; #ifdef MSW - if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0) - strcpy(cmdbuf, "."); -#endif -#ifdef UNIX - if (!getcwd(cmdbuf, MAXPDSTRING)) - strcpy(cmdbuf, "."); - -#endif - SETSYMBOL(zz, gensym(cmdbuf)); - for (i = 1; i < 22; i++) - SETFLOAT(zz + i, defaultfontshit[i-1]); - SETFLOAT(zz+22,0); - glob_initfromgui(0, 0, 23, zz); + if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0) + strcpy(cmdbuf, "."); +#endif +#ifdef UNISTD + if (!getcwd(cmdbuf, MAXPDSTRING)) + strcpy(cmdbuf, "."); + +#endif + SETSYMBOL(zz, gensym(cmdbuf)); + for (i = 1; i < 22; i++) + SETFLOAT(zz + i, defaultfontshit[i-1]); + SETFLOAT(zz+22,0); + glob_initfromgui(0, 0, 23, zz); } - else + else if (sys_guisetportnumber) /* GUI exists and sent us a port number */ + { + struct sockaddr_in server; + struct hostent *hp; + /* create a socket */ + sys_guisock = socket(AF_INET, SOCK_STREAM, 0); + if (sys_guisock < 0) + sys_sockerror("socket"); + + /* connect socket using hostname provided in command line */ + server.sin_family = AF_INET; + + hp = gethostbyname(LOCALHOST); + + if (hp == 0) + { + fprintf(stderr, + "localhost not found (inet protocol not installed?)\n"); + exit(1); + } + memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + + /* assign client port number */ + server.sin_port = htons((unsigned short)sys_guisetportnumber); + + /* try to connect */ + if (connect(sys_guisock, (struct sockaddr *) &server, sizeof (server)) + < 0) + { + sys_sockerror("connecting stream socket"); + exit(1); + } + } + else /* default behavior: start up the GUI ourselves. */ { #ifdef MSW - char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80]; - int spawnret; + char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80]; + int spawnret; #endif #ifdef MSW - char intarg; + char intarg; #else - int intarg; + int intarg; #endif - /* create a socket */ - xsock = socket(AF_INET, SOCK_STREAM, 0); - if (xsock < 0) sys_sockerror("socket"); + /* create a socket */ + xsock = socket(AF_INET, SOCK_STREAM, 0); + if (xsock < 0) sys_sockerror("socket"); #if 0 - intarg = 0; - if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF, - &intarg, sizeof(intarg)) < 0) - post("setsockopt (SO_RCVBUF) failed\n"); - intarg = 0; - if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF, - &intarg, sizeof(intarg)) < 0) - post("setsockopt (SO_RCVBUF) failed\n"); -#endif - intarg = 1; - if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY, - &intarg, sizeof(intarg)) < 0) + intarg = 0; + if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF, + &intarg, sizeof(intarg)) < 0) + post("setsockopt (SO_RCVBUF) failed\n"); + intarg = 0; + if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF, + &intarg, sizeof(intarg)) < 0) + post("setsockopt (SO_RCVBUF) failed\n"); +#endif + intarg = 1; + if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY, + &intarg, sizeof(intarg)) < 0) #ifndef MSW - post("setsockopt (TCP_NODELAY) failed\n") + post("setsockopt (TCP_NODELAY) failed\n") #endif - ; - - - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - - /* assign server port number */ - server.sin_port = htons((unsigned short)portno); - - /* name the socket */ - while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0) - { + ; + + + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + + /* assign server port number */ + server.sin_port = htons((unsigned short)portno); + + /* name the socket */ + while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0) + { #ifdef MSW - int err = WSAGetLastError(); -#endif -#ifdef UNIX - int err = errno; -#endif - if ((ntry++ > 20) || (err != EADDRINUSE)) - { - perror("bind"); - fprintf(stderr, - "Pd needs your machine to be configured with\n"); - fprintf(stderr, - "'networking' turned on (see Pd's html doc for details.)\n"); - exit(1); - } - portno++; - server.sin_port = htons((unsigned short)(portno)); - } - - if (sys_verbose) fprintf(stderr, "port %d\n", portno); - - sys_socketreceiver = socketreceiver_new(0, 0, 0, 0); - -#ifdef UNIX - childpid = fork(); - if (childpid < 0) - { + int err = WSAGetLastError(); +#else + int err = errno; +#endif + if ((ntry++ > 20) || (err != EADDRINUSE)) + { + perror("bind"); + fprintf(stderr, + "Pd needs your machine to be configured with\n"); + fprintf(stderr, + "'networking' turned on (see Pd's html doc for details.)\n"); + exit(1); + } + portno++; + server.sin_port = htons((unsigned short)(portno)); + } + + if (sys_verbose) fprintf(stderr, "port %d\n", portno); + + +#ifdef UNISTD + childpid = fork(); + if (childpid < 0) + { if (errno) perror("sys_startgui"); - else fprintf(stderr, "sys_startgui failed\n"); - return (1); - } - else if (!childpid) /* we're the child */ - { - seteuid(getuid()); /* lose setuid priveliges */ + else fprintf(stderr, "sys_startgui failed\n"); + return (1); + } + else if (!childpid) /* we're the child */ + { + seteuid(getuid()); /* lose setuid priveliges */ #ifndef MACOSX - /* the wish process in Unix will make a wish shell and - read/write standard in and out unless we close the - file descriptors. Somehow this doesn't make the MAC OSX - version of Wish happy...*/ - if (pipe(stdinpipe) < 0) - sys_sockerror("pipe"); - else - { - if (stdinpipe[0] != 0) - { - close (0); - dup2(stdinpipe[0], 0); - close(stdinpipe[0]); - } - } -#endif - if (!sys_guicmd) - { + /* the wish process in Unix will make a wish shell and + read/write standard in and out unless we close the + file descriptors. Somehow this doesn't make the MAC OSX + version of Wish happy...*/ + if (pipe(stdinpipe) < 0) + sys_sockerror("pipe"); + else + { + if (stdinpipe[0] != 0) + { + close (0); + dup2(stdinpipe[0], 0); + close(stdinpipe[0]); + } + } +#endif + if (!sys_guicmd) + { #ifdef MACOSX char *homedir = getenv("HOME"), filename[250]; struct stat statbuf; @@ -728,117 +1023,116 @@ int sys_startgui(const char *guidir) strcpy(filename, "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell"); foundit: - sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno); + sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno); #else - sprintf(cmdbuf, + sprintf(cmdbuf, "TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \ \"%s/pd-gui\" %d\n", - sys_libdir->s_name, sys_libdir->s_name, guidir, portno); + sys_libdir->s_name, sys_libdir->s_name, guidir, portno); #endif - sys_guicmd = cmdbuf; - } - if (sys_verbose) fprintf(stderr, "%s", sys_guicmd); - execl("/bin/sh", "sh", "-c", sys_guicmd, 0); - perror("pd: exec"); - _exit(1); - } -#endif /* UNIX */ + sys_guicmd = cmdbuf; + } + if (sys_verbose) fprintf(stderr, "%s", sys_guicmd); + execl("/bin/sh", "sh", "-c", sys_guicmd, 0); + perror("pd: exec"); + _exit(1); + } +#endif /* UNISTD */ #ifdef MSW - /* in MSW land "guipath" is unused; we just do everything from - the libdir. */ - /* fprintf(stderr, "%s\n", sys_libdir->s_name); */ - - strcpy(scriptbuf, "\""); - strcat(scriptbuf, sys_libdir->s_name); - strcat(scriptbuf, "/" PDBINDIR "pd.tk\""); - sys_bashfilename(scriptbuf, scriptbuf); - - sprintf(portbuf, "%d", portno); - - strcpy(wishbuf, sys_libdir->s_name); - strcat(wishbuf, "/" PDBINDIR WISHAPP); - sys_bashfilename(wishbuf, wishbuf); - - spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0); - if (spawnret < 0) - { - perror("spawnl"); - fprintf(stderr, "%s: couldn't load TCL\n", wishbuf); - exit(1); - } + /* in MSW land "guipath" is unused; we just do everything from + the libdir. */ + /* fprintf(stderr, "%s\n", sys_libdir->s_name); */ + + strcpy(scriptbuf, "\""); + strcat(scriptbuf, sys_libdir->s_name); + strcat(scriptbuf, "/" PDBINDIR "pd.tk\""); + sys_bashfilename(scriptbuf, scriptbuf); + + sprintf(portbuf, "%d", portno); + + strcpy(wishbuf, sys_libdir->s_name); + strcat(wishbuf, "/" PDBINDIR WISHAPP); + sys_bashfilename(wishbuf, wishbuf); + + spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0); + if (spawnret < 0) + { + perror("spawnl"); + fprintf(stderr, "%s: couldn't load TCL\n", wishbuf); + exit(1); + } #endif /* MSW */ } -#ifdef __linux__ - /* now that we've spun off the child process we can promote - our process's priority, if we happen to be root. */ +#if defined(__linux__) || defined(IRIX) + /* now that we've spun off the child process we can promote + our process's priority, if we can and want to. If not specfied + (-1), we check root status. This misses the case where we might + have permission from a "security module" (linux 2.6) -- I don't + know how to test for that. The "-rt" flag must b eset in that + case. */ + if (sys_hipriority == -1) + sys_hipriority = (!getuid() || !geteuid()); + if (sys_hipriority) { - if (!getuid() || !geteuid()) - { - /* To prevent lockup, we fork off a watchdog process with - higher real-time priority than ours. The GUI has to send - a stream of ping messages to the watchdog THROUGH the Pd - process which has to pick them up from the GUI and forward - them. If any of these things aren't happening the watchdog - starts sending "stop" and "cont" signals to the Pd process - to make it timeshare with the rest of the system. (Version - 0.33P2 : if there's no GUI, the watchdog pinging is done - from the scheduler idle routine in this process instead.) */ - - int pipe9[2], watchpid; - if (pipe(pipe9) < 0) - { - seteuid(getuid()); /* lose setuid priveliges */ - sys_sockerror("pipe"); - return (1); - } - watchpid = fork(); - if (watchpid < 0) - { - seteuid(getuid()); /* lose setuid priveliges */ - if (errno) - perror("sys_startgui"); - else fprintf(stderr, "sys_startgui failed\n"); - return (1); - } - else if (!watchpid) /* we're the child */ - { - sys_set_priority(1); - seteuid(getuid()); /* lose setuid priveliges */ - if (pipe9[1] != 0) - { - dup2(pipe9[0], 0); - close(pipe9[0]); - } - close(pipe9[1]); - - sprintf(cmdbuf, "%s/pd-watchdog\n", guidir); - if (sys_verbose) fprintf(stderr, "%s", cmdbuf); - execl("/bin/sh", "sh", "-c", cmdbuf, 0); - perror("pd: exec"); - _exit(1); - } - else /* we're the parent */ - { - sys_set_priority(0); - seteuid(getuid()); /* lose setuid priveliges */ - close(pipe9[0]); - sys_watchfd = pipe9[1]; - /* We also have to start the ping loop in the GUI; - this is done later when the socket is open. */ - } - } - else - { - post("realtime setting failed because not root\n"); - sys_hipriority = 0; - } + /* To prevent lockup, we fork off a watchdog process with + higher real-time priority than ours. The GUI has to send + a stream of ping messages to the watchdog THROUGH the Pd + process which has to pick them up from the GUI and forward + them. If any of these things aren't happening the watchdog + starts sending "stop" and "cont" signals to the Pd process + to make it timeshare with the rest of the system. (Version + 0.33P2 : if there's no GUI, the watchdog pinging is done + from the scheduler idle routine in this process instead.) */ + + int pipe9[2], watchpid; + if (pipe(pipe9) < 0) + { + seteuid(getuid()); /* lose setuid priveliges */ + sys_sockerror("pipe"); + return (1); + } + watchpid = fork(); + if (watchpid < 0) + { + seteuid(getuid()); /* lose setuid priveliges */ + if (errno) + perror("sys_startgui"); + else fprintf(stderr, "sys_startgui failed\n"); + return (1); + } + else if (!watchpid) /* we're the child */ + { + sys_set_priority(1); + seteuid(getuid()); /* lose setuid priveliges */ + if (pipe9[1] != 0) + { + dup2(pipe9[0], 0); + close(pipe9[0]); + } + close(pipe9[1]); + + sprintf(cmdbuf, "%s/pd-watchdog\n", guidir); + if (sys_verbose) fprintf(stderr, "%s", cmdbuf); + execl("/bin/sh", "sh", "-c", cmdbuf, 0); + perror("pd: exec"); + _exit(1); + } + else /* we're the parent */ + { + sys_set_priority(0); + seteuid(getuid()); /* lose setuid priveliges */ + close(pipe9[0]); + sys_watchfd = pipe9[1]; + /* We also have to start the ping loop in the GUI; + this is done later when the socket is open. */ + } } - seteuid(getuid()); /* lose setuid priveliges */ + seteuid(getuid()); /* lose setuid priveliges */ #endif /* __linux__ */ #ifdef MSW @@ -848,60 +1142,51 @@ int sys_startgui(const char *guidir) #ifdef MACOSX if (sys_hipriority) { - struct sched_param param; - int policy = SCHED_RR; - int err; - param.sched_priority = 80; // adjust 0 : 100 - - err = pthread_setschedparam(pthread_self(), policy, ¶m); - if (err) - post("warning: high priority scheduling failed\n"); + struct sched_param param; + int policy = SCHED_RR; + int err; + param.sched_priority = 80; // adjust 0 : 100 + + err = pthread_setschedparam(pthread_self(), policy, ¶m); + if (err) + post("warning: high priority scheduling failed\n"); } #endif /* MACOSX */ - if (!sys_nogui) + if (!sys_nogui && !sys_guisetportnumber) { - char buf[256]; - if (sys_verbose) - fprintf(stderr, "Waiting for connection request... \n"); - if (listen(xsock, 5) < 0) sys_sockerror("listen"); + if (sys_verbose) + fprintf(stderr, "Waiting for connection request... \n"); + if (listen(xsock, 5) < 0) sys_sockerror("listen"); - sys_guisock = accept(xsock, (struct sockaddr *) &server, &len); + sys_guisock = accept(xsock, (struct sockaddr *) &server, &len); #ifdef OOPS - close(xsock); + close(xsock); #endif - if (sys_guisock < 0) sys_sockerror("accept"); - sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read, - sys_socketreceiver); - - if (sys_verbose) - fprintf(stderr, "... connected\n"); - - /* here is where we start the pinging. */ -#ifdef __linux__ - if (sys_hipriority) - sys_gui("pdtk_watchdog\n"); + if (sys_guisock < 0) sys_sockerror("accept"); + if (sys_verbose) + fprintf(stderr, "... connected\n"); + } + if (!sys_nogui) + { + char buf[256]; + sys_socketreceiver = socketreceiver_new(0, 0, 0, 0); + sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read, + sys_socketreceiver); + + /* here is where we start the pinging. */ +#if defined(__linux__) || defined(IRIX) + if (sys_hipriority) + sys_gui("pdtk_watchdog\n"); #endif - sys_get_audio_apis(buf); - sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf); + sys_get_audio_apis(buf); + sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf); } return (0); } -static int sys_poll_togui(void) -{ - /* LATER use this to flush output buffer to gui */ - return (0); -} - -int sys_pollgui(void) -{ - return (sys_domicrosleep(0, 1) || sys_poll_togui()); -} - - /* T.Grill - import clean quit function */ extern void sys_exit(void); @@ -913,15 +1198,15 @@ void sys_bail(int n) static int reentered = 0; if (!reentered) { - reentered = 1; -#ifndef __linux /* sys_close_audio() hangs if you're in a signal? */ - fprintf(stderr, "closing audio...\n"); - sys_close_audio(); - fprintf(stderr, "closing MIDI...\n"); - sys_close_midi(); - fprintf(stderr, "... done.\n"); -#endif - exit(1); + reentered = 1; +#ifndef __linux__ /* sys_close_audio() hangs if you're in a signal? */ + fprintf(stderr, "closing audio...\n"); + sys_close_audio(); + fprintf(stderr, "closing MIDI...\n"); + sys_close_midi(); + fprintf(stderr, "... done.\n"); +#endif + exit(1); } else _exit(n); } @@ -931,8 +1216,8 @@ void glob_quit(void *dummy) sys_vgui("exit\n"); if (!sys_nogui) { - close(sys_guisock); - sys_rmpollfn(sys_guisock); + close(sys_guisock); + sys_rmpollfn(sys_guisock); } sys_bail(0); } |