diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c
index 486ae7b0c18ac86e5c33c7511fc59891fe8d81a2..ffaf865139c8fd3eb1d846fc6960a6ac86033b5f 100644
--- a/pd/src/s_inter.c
+++ b/pd/src/s_inter.c
@@ -291,12 +291,39 @@ void sys_setalarm(int microsec)
 
 #endif
 
-#ifdef __linux
+void sys_setsignalhandlers(void)
+{
+#if !defined(_WIN32) && !defined(__CYGWIN__)
+    signal(SIGHUP, sys_huphandler);
+    signal(SIGINT, sys_exithandler);
+    signal(SIGQUIT, sys_exithandler);
+    signal(SIGILL, sys_exithandler);
+# ifdef SIGIOT
+    signal(SIGIOT, sys_exithandler);
+# endif
+    signal(SIGFPE, SIG_IGN);
+    /* signal(SIGILL, sys_exithandler);
+    signal(SIGBUS, sys_exithandler);
+    signal(SIGSEGV, sys_exithandler); */
+    signal(SIGPIPE, SIG_IGN);
+    signal(SIGALRM, SIG_IGN);
+#if 0  /* GG says: don't use that */
+    signal(SIGSTKFLT, sys_exithandler);
+#endif
+#endif /* NOT _WIN32 && NOT __CYGWIN__ */
+}
+
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
+
 
 #if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK)
 #include <sched.h>
 #endif
 
+#define MODE_NRT 0
+#define MODE_RT 1
+#define MODE_WATCHDOG 2
+
 void sys_set_priority(int higher) 
 {
 #ifdef _POSIX_PRIORITY_SCHEDULING
@@ -1216,22 +1243,6 @@ int sys_startgui(const char *guidir)
     sys_nfdpoll = 0;
     inbinbuf = binbuf_new();
 
-#ifdef HAVE_UNISTD_H
-    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);
-#if 0  /* GG says: don't use that */
-    signal(SIGSTKFLT, sys_exithandler);
-#endif
-#endif
 #ifdef MSW
     if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
 #endif
@@ -1374,7 +1385,6 @@ int sys_startgui(const char *guidir)
             /* this glob is needed so the Wish executable can have the same
              * filename as the Pd.app, i.e. 'Pd-0.42-3.app' should have a Wish
              * executable called 'Pd-0.42-3.app/Contents/MacOS/Pd-0.42-3' */
-//            sprintf(embed_glob, "%s/../../MacOS/Pd*", guidir);
             sprintf(embed_glob, "%s/../../MacOS/nwjs", guidir);
             glob_buffer.gl_matchc = 1; /* we only need one match */
             glob(embed_glob, GLOB_LIMIT, NULL, &glob_buffer);
@@ -1408,7 +1418,7 @@ int sys_startgui(const char *guidir)
                use the nw binary and GUI code from your local
                copy of the Purr Data repo. (Make sure to run
                tar_em_up.sh first to fetch the nw binary.) */
-            //strcpy(guidir2, "\"/home/grieg/purr-data/pd/nw\"");
+            //strcpy(guidir2, "\"/home/user/purr-data/pd/nw\"");
             sprintf(cmdbuf,
                 "\"%s\" %s %s "
                 "%d localhost %s %s " X_SPECIFIER,
@@ -1449,7 +1459,7 @@ int sys_startgui(const char *guidir)
                use the nw binary and GUI code from your local
                copy of the Purr Data repo. (Make sure to run
                tar_em_up.sh first to fetch the nw binary.) */
-            //strcpy(guidir2, "\"/home/grieg/purr-data/pd/nw\"");
+            //strcpy(guidir2, "\"/home/user/purr-data/pd/nw\"");
             sprintf(cmdbuf,
                 "%s/nw/nw %s %s "
                 "%d localhost %s %s " X_SPECIFIER,
@@ -1472,11 +1482,15 @@ int sys_startgui(const char *guidir)
         {
             if (errno) perror("sys_startgui");
             else fprintf(stderr, "sys_startgui failed\n");
+            sys_closesocket(xsock);
             return (1);
         }
         else if (!childpid)                     /* we're the child */
         {
-            setuid(getuid());          /* lose setuid priveliges */
+            sys_closesocket(xsock); /* we're the child */
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
+            sys_set_priority(MODE_NRT);
+#endif
 #ifndef __APPLE__
                 /* the wish process in Unix will make a wish shell and
                     read/write standard in and out unless we close the
@@ -1548,23 +1562,101 @@ int sys_startgui(const char *guidir)
 #endif /* MSW */
     }
 
+    if (!sys_nogui && !sys_guisetportnumber)
+    {
+        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,
+            (socklen_t *)&len);
+#ifdef OOPS
+        sys_closesocket(xsock);
+#endif
+        if (sys_guisock < 0) sys_sockerror("accept");
+        if (sys_verbose)
+            fprintf(stderr, "... connected\n");
+    }
+    if (!sys_nogui)
+    {
+      char buf[256], buf2[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)
-        /* 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 assume real-time was wanted.  Afterward, just in case
-        someone made Pd setuid in order to get permission to do this,
-        unset setuid and lose root priveliges after doing this.  Starting
-        in Linux 2.6 this is accomplished by putting lines like:
+         if (sys_hipriority)
+             gui_vmess("gui_watchdog", "");
+#endif
+         sys_get_audio_apis(buf);
+         sys_get_midi_apis(buf2);
+
+        t_binbuf *aapis = binbuf_new(), *mapis = binbuf_new();
+        sys_get_audio_apis2(aapis);
+        sys_get_midi_apis2(mapis);
+        gui_start_vmess("gui_startup", "sss",
+		  pd_version,
+		  sys_font,
+		  sys_fontweight);
+
+        int i;
+        gui_start_array(); // audio apis
+        for (i = 0; i < binbuf_getnatom(aapis); i+=2)
+        {
+            gui_s(atom_getsymbol(binbuf_getvec(aapis)+i)->s_name);
+            gui_i(atom_getint(binbuf_getvec(aapis)+i+1));
+        }
+        gui_end_array();
+
+        gui_start_array(); // midi apis
+        for (i = 0; i < binbuf_getnatom(mapis); i+=2)
+        {
+            gui_s(atom_getsymbol(binbuf_getvec(mapis)+i)->s_name);
+            gui_i(atom_getint(binbuf_getvec(mapis)+i+1));
+        }
+        gui_end_array();
+
+        gui_end_vmess();
+        gui_vmess("gui_set_cwd", "xs", 0, cwd);
+        binbuf_free(aapis);
+        binbuf_free(mapis);
+    }
+    return (0);
+
+}
+
+void sys_setrealtime(const char *libdir)
+{
+    char cmdbuf[MAXPDSTRING];
+#if defined(__linux__) || defined(__FreeBSD_kernel__)
+        /*  promote this process's priority, if we can and want to.
+        If sys_hipriority not specfied (-1), we assume real-time was wanted.
+        Starting in Linux 2.6 one can permit real-time operation of Pd by
+        putting lines like:
                 @audio - rtprio 99
                 @audio - memlock unlimited
         in the system limits file, perhaps /etc/limits.conf or
-        /etc/security/limits.conf */
+        /etc/security/limits.conf, and calling Pd from a user in group audio. */
     if (sys_hipriority == -1)
-        sys_hipriority = 1; //(!getuid() || !geteuid());
-    
-    sprintf(cmdbuf, "%s/pd-watchdog\n", guidir);
+        sys_hipriority = 1;
+
+    snprintf(cmdbuf, MAXPDSTRING, "%s/bin/pd-watchdog", libdir);
+    cmdbuf[MAXPDSTRING-1] = 0;
     if (sys_hipriority)
     {
+        struct stat statbuf;
+        if (stat(cmdbuf, &statbuf) < 0)
+        {
+            fprintf(stderr,
+              "disabling real-time priority due to missing pd-watchdog (%s)\n",
+                cmdbuf);
+            sys_hipriority = 0;
+        }
+    }
+    if (sys_hipriority)
+    {
+        int pipe9[2], watchpid;
             /* 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
@@ -1574,27 +1666,23 @@ int sys_startgui(const char *guidir)
             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)
         {
-            setuid(getuid());      /* lose setuid priveliges */
             sys_sockerror("pipe");
-            return (1);
+            return;
         }
         watchpid = fork();
         if (watchpid < 0)
         {
-            setuid(getuid());      /* lose setuid priveliges */
             if (errno)
-                perror("sys_startgui");
-            else fprintf(stderr, "sys_startgui failed\n");
-            return (1);
+                perror("sys_setpriority");
+            else fprintf(stderr, "sys_setpriority failed\n");
+            return;
         }
         else if (!watchpid)             /* we're the child */
         {
-            sys_set_priority(1);
-            setuid(getuid());      /* lose setuid priveliges */
+            sys_set_priority(MODE_WATCHDOG);
             if (pipe9[1] != 0)
             {
                 dup2(pipe9[0], 0);
@@ -1602,26 +1690,31 @@ int sys_startgui(const char *guidir)
             }
             close(pipe9[1]);
 
-            if (sys_verbose) fprintf(stderr, "%s", cmdbuf);
+            if (sys_verbose) fprintf(stderr, "%s\n", cmdbuf);
             execl("/bin/sh", "sh", "-c", cmdbuf, (char*)0);
             perror("pd: exec");
             _exit(1);
         }
         else                            /* we're the parent */
         {
-            sys_set_priority(0);
-            setuid(getuid());      /* lose setuid priveliges */
+            sys_set_priority(MODE_RT);
             close(pipe9[0]);
+                /* set close-on-exec so that watchdog will see an EOF when we
+                close our copy - otherwise it might hang waiting for some
+                stupid child process (as seems to happen if jackd auto-starts
+                for us.) */
+            if(fcntl(pipe9[1], F_SETFD, FD_CLOEXEC) < 0)
+              perror("close-on-exec");
             sys_watchfd = pipe9[1];
                 /* We also have to start the ping loop in the GUI;
                 this is done later when the socket is open. */
         }
     }
-
-    setuid(getuid());          /* lose setuid priveliges */
+    else if (sys_verbose)
+        post("not setting real-time priority");
 #endif /* __linux__ */
 
-#ifdef MSW
+#ifdef _WIN32
     if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
         fprintf(stderr, "pd: couldn't set high priority class\n");
 #endif
@@ -1638,71 +1731,6 @@ int sys_startgui(const char *guidir)
             post("warning: high priority scheduling failed\n");
     }
 #endif /* __APPLE__ */
-
-    if (!sys_nogui && !sys_guisetportnumber)
-    {
-        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, 
-            (socklen_t *)&len);
-#ifdef OOPS
-        sys_closesocket(xsock);
-#endif
-        if (sys_guisock < 0) sys_sockerror("accept");
-        if (sys_verbose)
-            fprintf(stderr, "... connected\n");
-    }
-    if (!sys_nogui)
-    {
-      char buf[256], buf2[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)
-             gui_vmess("gui_watchdog", "");
-#endif
-         sys_get_audio_apis(buf);
-         sys_get_midi_apis(buf2);
-//         sys_vgui("pdtk_pd_startup {%s} %s %s {%s} %s\n", pd_version, buf, buf2, 
-//                  sys_font, sys_fontweight); 
-
-        t_binbuf *aapis = binbuf_new(), *mapis = binbuf_new();
-        sys_get_audio_apis2(aapis);
-        sys_get_midi_apis2(mapis);
-        gui_start_vmess("gui_startup", "sss",
-		  pd_version,
-		  sys_font,
-		  sys_fontweight);
-
-        int i;
-        gui_start_array(); // audio apis
-        for (i = 0; i < binbuf_getnatom(aapis); i+=2)
-        {
-            gui_s(atom_getsymbol(binbuf_getvec(aapis)+i)->s_name);
-            gui_i(atom_getint(binbuf_getvec(aapis)+i+1));
-        }
-        gui_end_array();
-
-        gui_start_array(); // midi apis
-        for (i = 0; i < binbuf_getnatom(mapis); i+=2)
-        {
-            gui_s(atom_getsymbol(binbuf_getvec(mapis)+i)->s_name);
-            gui_i(atom_getint(binbuf_getvec(mapis)+i+1));
-        }
-        gui_end_array();
-
-        gui_end_vmess();
-        gui_vmess("gui_set_cwd", "xs", 0, cwd);
-        binbuf_free(aapis);
-        binbuf_free(mapis);
-    }
-    return (0);
-
 }
 
 extern void sys_exit(void);
diff --git a/pd/src/s_main.c b/pd/src/s_main.c
index 2f7650824491f43a6482674f5f6ec294086e4d3b..41ee4e19a10da4078df293ead6a1f69eb1feb44d 100644
--- a/pd/src/s_main.c
+++ b/pd/src/s_main.c
@@ -32,7 +32,9 @@ static const char pd_compiledate[] = __DATE__;
 void pd_init(void);
 int sys_argparse(int argc, char **argv);
 void sys_findprogdir(char *progname);
+void sys_setsignalhandlers(void);
 int sys_startgui(const char *guipath);
+void sys_setrealtime(const char *guipath);
 int sys_rcfile(void);
 int m_mainloop(void);
 int m_batchmain(void);
@@ -344,6 +346,16 @@ int sys_main(int argc, char **argv)
         _fmode = _O_BINARY;
     }
 # endif /* _MSC_VER */
+#endif  /* _WIN32 */
+#ifndef _WIN32
+    /* long ago Pd used setuid to promote itself to real-time priority.
+    Just in case anyone's installation script still makes it setuid, we
+    complain to stderr and lose setuid here. */
+    if (getuid() != geteuid())
+    {
+        fprintf(stderr, "warning: canceling setuid privilege\n");
+        setuid(getuid());
+    }
 #endif  /* _WIN32 */
     pd_init();                                  /* start the message system */
     sys_findprogdir(argv[0]);                   /* set sys_progname, guipath */
@@ -366,6 +378,7 @@ int sys_main(int argc, char **argv)
         pd_version, pd_compiletime, pd_compiledate);
     if (sys_version)    /* if we were just asked our version, exit here. */
         return (0);
+    sys_setsignalhandlers();
     if (sys_nogui)
         clock_set((sys_fakefromguiclk =
             clock_new(0, (t_method)sys_fakefromgui)), 0);
@@ -389,6 +402,8 @@ int sys_main(int argc, char **argv)
     gui_end_array();
     gui_end_vmess();
 
+    if (sys_hipriority)
+        sys_setrealtime(sys_libdir->s_name); /* set desired process priority */
     if (sys_externalschedlib)
         return (sys_run_scheduler(sys_externalschedlibname,
             sys_extraflagsstring));