tNo more malloc or lock inside signal handlers. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 175b8a534ae5729ac10ea793410a40bfa4a30608
 (DIR) parent ac0e2db600593d5b30550453b78874bfa0611751
 (HTM) Author: rsc <devnull@localhost>
       Date:   Wed, 21 Apr 2004 04:48:25 +0000
       
       No more malloc or lock inside signal handlers.
       
       Diffstat:
         M src/lib9/9proc.h                    |       5 +----
         M src/lib9/_p9proc.c                  |     110 +++++++++++++++++++-------------
         M src/lib9/notify.c                   |       5 +++--
         M src/lib9/priv.c                     |       2 +-
         M src/lib9/rendez.c                   |       2 +-
         M src/lib9/rfork.c                    |       7 +++++--
       
       6 files changed, 77 insertions(+), 54 deletions(-)
       ---
 (DIR) diff --git a/src/lib9/9proc.h b/src/lib9/9proc.h
       t@@ -2,15 +2,12 @@ enum
        {
                NPRIV = 16,
                RENDHASH = 33,
       -        PIDHASH = 33,
        };
        
        typedef struct Uproc Uproc;
        struct Uproc
        {
       -        Uproc *next;
                int pid;
       -        int pipe[2];
                int state;
                void *priv[NPRIV];
                ulong rendval;
       t@@ -19,5 +16,5 @@ struct Uproc
                p9jmp_buf notejb;
        };
        
       -extern Uproc *_p9uproc(void);
       +extern Uproc *_p9uproc(int);
        extern void _p9uprocdie(void);
 (DIR) diff --git a/src/lib9/_p9proc.c b/src/lib9/_p9proc.c
       t@@ -1,73 +1,95 @@
       +/*
       + * This needs to be callable from a signal handler, so it has been
       + * written to avoid locks.  The only lock is the one used to acquire
       + * an entry in the table, and we make sure that acquiring is done
       + * when not in a handler.  Lookup and delete do not need locks.
       + * It's a scan-forward hash table.  To avoid breaking chains, 
       + * T ((void*)-1) is used as a non-breaking nil.
       + */
       +
        #include <u.h>
        #include <libc.h>
        #include "9proc.h"
        
       +enum { PIDHASH = 1021 };
       +
       +#define T ((void*)-1)
       +static Uproc *alluproc[PIDHASH];
       +static int allupid[PIDHASH];
        static Lock uproclock;
       -static Uproc *phash[PIDHASH];
        
        Uproc*
       -_p9uproc(void)
       +_p9uproc(int inhandler)
        {
       -        /* for now, assume getpid is fast or cached */
       -        int pid;
       +        int i, h, pid;
                Uproc *up;
        
       +        /* for now, assume getpid is fast or cached */
                pid = getpid();
       -again:
       -if(0)print("find %d\n", pid);
       -        lock(&uproclock);
       -        for(up=phash[pid%PIDHASH]; up; up=up->next){
       -                if(up->pid == pid){
       -if(0)print("found %d\n", pid);
       -                        unlock(&uproclock);
       +
       +        /*
       +         * this part - the lookup - needs to run without locks
       +         * so that it can safely be called from within the notify handler.
       +         * notify calls _p9uproc, and fork and rfork call _p9uproc
       +         * in both parent and child, so if we're in a signal handler,
       +         * we should find something in the table.
       +         */
       +        h = pid%PIDHASH;
       +        for(i=0; i<PIDHASH; i++){
       +                up = alluproc[h];
       +                if(up == nil)
       +                        break;
       +                if(allupid[h] == pid)
                                return up;
       -                }
       +                if(++h == PIDHASH)
       +                        h = 0;
                }
        
       -        up = mallocz(sizeof(Uproc), 1);
       -        if(up == nil){
       -if(0)print("again %d\n", pid);
       -                unlock(&uproclock);
       -                sleep(1000);
       -                goto again;
       -        }
       +        if(inhandler)
       +                sysfatal("did not find uproc in signal handler");
        
       -againpipe:
       -        if(pipe(up->pipe) < 0){
       -if(0)print("againpipe %d\n", pid);
       +        /* need to allocate */
       +        while((up = mallocz(sizeof(Uproc), 1)) == nil)
                        sleep(1000);
       -                goto againpipe;
       -        }
        
       -        up->pid = pid;
       -        up->next = phash[pid%PIDHASH];
       -        phash[pid%PIDHASH] = up;
       -if(0)print("link %d\n", pid);
       +        up = mallocz(sizeof(Uproc), 1);
       +        lock(&uproclock);
       +        h = pid%PIDHASH;
       +        for(i=0; i<PIDHASH; i++){
       +                if(alluproc[h]==T || alluproc[h]==nil){
       +                        alluproc[h] = up;
       +                        allupid[h] = pid;
       +                        return up;
       +                }
       +                if(++h == PIDHASH)
       +                        h = 0;
       +        }
                unlock(&uproclock);
       -        return up;
       +
       +        /* out of pids! */
       +        sysfatal("too many processes in uproc table");
       +        return nil;
        }
        
        void
        _p9uprocdie(void)
        {
       -        Uproc **l, *up;
       -        int pid;
       +        Uproc *up;
       +        int pid, i, h;
        
                pid = getpid();
       -if(0)print("die %d\n", pid);
       -        lock(&uproclock);
       -        for(l=&phash[pid%33]; *l; l=&(*l)->next){
       -                if((*l)->pid == pid){
       -                        up = *l;
       -                        *l = up->next;
       -if(0)print("died %d\n", pid);
       -                        unlock(&uproclock);
       -                        close(up->pipe[0]);
       -                        close(up->pipe[1]);
       +        h = pid%PIDHASH;
       +        for(i=0; i<PIDHASH; i++){
       +                up = alluproc[h];
       +                if(up == nil)
       +                        break;
       +                if(up == T)
       +                        continue;
       +                if(allupid[h] == pid){
       +                        up = alluproc[h];
       +                        alluproc[h] = T;
                                free(up);
       -                        return;
       +                        allupid[h] = 0;
                        }
                }
       -if(0)print("not started %d\n", pid);
       -        unlock(&uproclock);
        }
 (DIR) diff --git a/src/lib9/notify.c b/src/lib9/notify.c
       t@@ -49,7 +49,7 @@ notifysigf(int sig)
                char tmp[64];
                Uproc *up;
        
       -        up = _p9uproc();
       +        up = _p9uproc(1);
                v = p9setjmp(up->notejb);
                if(v == 0 && notifyf)
                        (*notifyf)(nil, _p9sigstr(sig, tmp));
       t@@ -68,6 +68,7 @@ notify(void (*f)(void*, char*))
                int i;
                struct sigaction sa;
        
       +        _p9uproc(0);
                memset(&sa, 0, sizeof sa);
                if(f == 0)
                        sa.sa_handler = SIG_DFL;
       t@@ -90,7 +91,7 @@ noted(int v)
        {
                Uproc *up;
        
       -        up = _p9uproc();
       +        up = _p9uproc(1);
                p9longjmp(up->notejb, v==NCONT ? 2 : 1);
                abort();
                return 0;
 (DIR) diff --git a/src/lib9/priv.c b/src/lib9/priv.c
       t@@ -26,7 +26,7 @@ privmem(int i)
        {
                Uproc *up;
        
       -        up = _p9uproc();
       +        up = _p9uproc(0);
                return &up->priv[i];
        }
        
 (DIR) diff --git a/src/lib9/rendez.c b/src/lib9/rendez.c
       t@@ -12,7 +12,7 @@ rendezvous(ulong tag, ulong val)
                ulong ret;
                Uproc *t, *self, **l;
        
       -        self = _p9uproc();
       +        self = _p9uproc(0);
                lock(&rendlock);
                l = &rendhash[tag%RENDHASH];
                for(t=*l; t; l=&t->rendhash, t=*l){
 (DIR) diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
       t@@ -1,5 +1,7 @@
       -#define NOPLAN9DEFINES
       -#include <lib9.h>
       +#include <u.h>
       +#include <libc.h>
       +#include "9proc.h"
       +#undef rfork
        
        int
        p9rfork(int flags)
       t@@ -14,6 +16,7 @@ p9rfork(int flags)
                                return -1;
                        }
                        pid = fork();
       +                _p9uproc(0);
                        if(pid != 0)
                                return pid;
                }