rockbox/apps/plugins/pdbox/PDa/src/s_inter.c
Peter D'Hoye 526b5580da Cut the files in half and it might work better (note to self: check your tree is really clean before patching)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21070 a1c6a512-1295-4272-9138-f99709370657
2009-05-24 21:28:16 +00:00

1000 lines
24 KiB
C

/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
/* Pd side of the Pd/Pd-gui interface. Also, some system interface routines
that didn't really belong anywhere. */
#include "m_pd.h"
#include "s_stuff.h"
#include "m_imp.h"
#ifdef UNIX
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/mman.h>
#endif
#ifdef HAVE_BSTRING_H
#include <bstring.h>
#endif
#ifdef MSW
#include <io.h>
#include <fcntl.h>
#include <process.h>
#include <winsock.h>
typedef int pid_t;
#define EADDRINUSE WSAEADDRINUSE
#endif
#include <stdarg.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#ifdef MACOSX
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#else
#include <stdlib.h>
#endif
#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... */
#ifndef PDBINDIR
#define PDBINDIR "bin/"
#endif
#ifndef WISHAPP
#define WISHAPP "wish83.exe"
#endif
extern char pd_version[];
typedef struct _fdpoll
{
int fdp_fd;
t_fdpollfn fdp_fn;
void *fdp_ptr;
} t_fdpoll;
#define INBUFSIZE 4096
struct _socketreceiver
{
char *sr_inbuf;
int sr_inhead;
int sr_intail;
void *sr_owner;
int sr_udp;
t_socketnotifier sr_notifier;
t_socketreceivefn sr_socketreceivefn;
};
static int sys_nfdpoll;
static t_fdpoll *sys_fdpoll;
static int sys_maxfd;
static int sys_guisock;
static t_binbuf *inbinbuf;
static t_socketreceiver *sys_socketreceiver;
extern int sys_addhist(int phase);
#ifdef MSW
static LARGE_INTEGER nt_inittime;
static double nt_freq = 0;
static void sys_initntclock(void)
{
LARGE_INTEGER f1;
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
if (!QueryPerformanceFrequency(&f1))
{
fprintf(stderr, "pd: QueryPerformanceFrequency failed\n");
f1.QuadPart = 1;
}
nt_freq = f1.QuadPart;
nt_inittime = now;
}
#if 0
/* this is a version you can call if you did the QueryPerformanceCounter
call yourself. Necessary for time tagging incoming MIDI at interrupt
level, for instance; but we're not doing that just now. */
double nt_tixtotime(LARGE_INTEGER *dumbass)
{
if (nt_freq == 0) sys_initntclock();
return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq);
}
#endif
#endif /* MSW */
/* get "real time" in seconds; take the
first time we get called as a reference time of zero. */
t_time sys_getrealtime(void)
{
#ifdef UNIX
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)*1000000 +
(now.tv_usec - then.tv_usec);
#endif
#ifdef MSW
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
if (nt_freq == 0) sys_initntclock();
return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq);
#endif
}
void sys_sockerror(char *s)
{
#ifdef MSW
int err = WSAGetLastError();
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");
}
#endif
#ifdef UNIX
int err = errno;
#endif
fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
}
void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr)
{
int nfd = sys_nfdpoll;
int size = nfd * sizeof(t_fdpoll);
t_fdpoll *fp;
sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
size + sizeof(t_fdpoll));
fp = sys_fdpoll + nfd;
fp->fdp_fd = fd;
fp->fdp_fn = fn;
fp->fdp_ptr = ptr;
sys_nfdpoll = nfd + 1;
if (fd >= sys_maxfd) sys_maxfd = fd + 1;
}
void sys_rmpollfn(int fd)
{
int nfd = sys_nfdpoll;
int i, size = nfd * sizeof(t_fdpoll);
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;
}
}
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)
{
t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x));
x->sr_inhead = x->sr_intail = 0;
x->sr_owner = owner;
x->sr_notifier = notifier;
x->sr_socketreceivefn = socketreceivefn;
x->sr_udp = udp;
if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_socketreceiver");;
return (x);
}
void socketreceiver_free(t_socketreceiver *x)
{
free(x->sr_inbuf);
freebytes(x, sizeof(*x));
}
/* this is in a separately called subroutine so that the buffer isn't
sitting on the stack while the messages are getting passed. */
static int socketreceiver_doread(t_socketreceiver *x)
{
char messbuf[INBUFSIZE], *bp = messbuf;
int indx;
int inhead = x->sr_inhead;
int intail = x->sr_intail;
char *inbuf = x->sr_inbuf;
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);
}
}
return (0);
}
static void socketreceiver_getudp(t_socketreceiver *x, int fd)
{
char buf[INBUFSIZE+1];
int ret = recv(fd, buf, INBUFSIZE, 0);
if (ret < 0)
{
sys_sockerror("recv");
sys_rmpollfn(fd);
sys_closesocket(fd);
}
else if (ret > 0)
{
buf[ret] = 0;
#if 0
post("%s", buf);
#endif
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");
}
}
}
#include <termios.h>
#include <string.h>
static struct termios stored_settings;
EXTERN int sys_stdin;
void set_keypress(void)
{
struct termios new_settings;
tcgetattr(0,&stored_settings);
new_settings = stored_settings;
/* Disable canonical mode, and set buffer size to 1 byte */
new_settings.c_lflag &= (~ICANON);
new_settings.c_cc[VTIME] = 0;
new_settings.c_cc[VMIN] = 1;
/* echo off */
new_settings.c_lflag &= (~ECHO);
tcsetattr(0,TCSANOW,&new_settings);
return;
}
void reset_keypress(void)
{
if (sys_stdin)
tcsetattr(0,TCSANOW,&stored_settings);
return;
}
static t_symbol* _ss;
void stdin_read(t_socketreceiver *x, int fd) {
static char input[256];
char* in;
int got;
got = read(fd,input,256);
in = input;
while (got-- && _ss->s_thing)
pd_float(_ss->s_thing,(float)*in++);
}
void socketreceiver_read(t_socketreceiver *x, int fd)
{
if (x->sr_udp) /* UDP ("datagram") socket protocol */
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);
}
}
}
}
}
void sys_closesocket(int fd)
{
#ifdef UNIX
close(fd);
#endif
#ifdef MSW
closesocket(fd);
#endif
}
void sys_gui(char *s)
{
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)
{
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;
}
}
sys_addhist(histwas);
}
/* LATER should do a bounds check -- but how do you get printf to do that?
See also rtext_senditup() in this regard */
void sys_vgui(char *fmt, ...)
{
int result, i;
char buf[2048];
va_list ap;
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
sys_gui(buf);
va_end(ap);
}
#define FIRSTPORTNUM 5400
/* -------------- signal handling for UNIX -------------- */
#ifdef UNIX
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__ */
static int sys_watchfd;
#ifdef __linux__
void glob_ping(t_pd *dummy)
{
if (write(sys_watchfd, "\n", 1) < 1)
{
fprintf(stderr, "pd: watchdog process died\n");
sys_bail(1);
}
}
#endif
static int defaultfontshit[] = {
8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28,
24, 15, 28};
int sys_startgui(const char *guidir)
{
pid_t childpid;
char cmdbuf[4*MAXPDSTRING];
struct sockaddr_in server;
int msgsock;
char buf[15];
int len = sizeof(server);
int ntry = 0, portno = FIRSTPORTNUM;
int xsock = -1;
#ifdef MSW
short version = MAKEWORD(2, 0);
WSADATA nobby;
#endif
#ifdef UNIX
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
signal(SIGHUP, sys_huphandler);
signal(SIGINT, sys_exithandler);
signal(SIGQUIT, sys_exithandler);
signal(SIGILL, sys_exithandler);
signal(SIGIOT, sys_exithandler);
signal(SIGFPE, SIG_IGN);
/* signal(SIGILL, sys_exithandler);
signal(SIGBUS, sys_exithandler);
signal(SIGSEGV, 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
#endif
#ifdef MSW
if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
#endif
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;
#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);
}
else
{
#ifdef MSW
char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80];
int spawnret;
#endif
#ifdef MSW
char intarg;
#else
int intarg;
#endif
/* 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)
#ifndef MSW
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)
{
#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)
{
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 */
#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)
{
#ifdef MACOSX
char *homedir = getenv("HOME"), filename[250];
struct stat statbuf;
if (!homedir || strlen(homedir) > 150)
goto nohomedir;
sprintf(filename,
"%s/Applications/Utilities/Wish shell.app/Contents/MacOS/Wish Shell",
homedir);
if (stat(filename, &statbuf) >= 0)
goto foundit;
sprintf(filename,
"%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell",
homedir);
if (stat(filename, &statbuf) >= 0)
goto foundit;
nohomedir:
strcpy(filename,
"/Applications/Utilities/Wish Shell.app/Contents/MacOS/Wish Shell");
if (stat(filename, &statbuf) >= 0)
goto foundit;
strcpy(filename,
"/Applications/Wish Shell.app/Contents/MacOS/Wish Shell");
foundit:
sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno);
#else
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);
#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 */
#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);
}
#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 (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;
}
}
seteuid(getuid()); /* lose setuid priveliges */
#endif /* __linux__ */
#ifdef MSW
if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
fprintf(stderr, "pd: couldn't set high priority class\n");
#endif
#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, &param);
if (err)
post("warning: high priority scheduling failed\n");
}
#endif /* MACOSX */
if (!sys_nogui)
{
char buf[256];
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);
#ifdef OOPS
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");
#endif
sys_get_audio_apis(buf);
sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf);
}
if (sys_stdin) {
set_keypress();
_ss = gensym("stdin");
sys_addpollfn(1, (t_fdpollfn) stdin_read,NULL);
}
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);
/* This is called when something bad has happened, like a segfault.
Call glob_quit() below to exit cleanly.
LATER try to save dirty documents even in the bad case. */
void sys_bail(int n)
{
static int reentered = 0;
reset_keypress();
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);
}
else _exit(n);
}
void glob_quit(void *dummy)
{
sys_vgui("exit\n");
if (!sys_nogui)
{
close(sys_guisock);
sys_rmpollfn(sys_guisock);
}
reset_keypress();
sys_bail(0);
}