> A simple change:
> pid = getpid();

shouldn't you just fix it so _tos->pid is set?

also, the comments in the new nsec.c don't
match the code.  the code looks something like this

        do{
                ...
                tries = 0;
        }while(tries++ == 0);   /* retry once */

of course either this should be

        /* just retry for ever */
        for(;;){
                ...
        }
or
        /* retry once */
        for(tries = 0; tries < 2; tries++)

also, there's nothing stoping the race between
- two procs allocating the same element of the pid array
- two procs opening the global fd twice

both cases have the potential to leak an unlimited amount
of file descriptors.  i've added a proposed change.

- erik

----
#include <u.h>
#include <libc.h>
#include <tos.h>

static uvlong order = 0x0001020304050607ULL;

static void
be2vlong(vlong *to, uchar *f)
{
        uchar *t, *o;
        int i;

        t = (uchar*)to;
        o = (uchar*)&order;
        for(i = 0; i < sizeof order; i++)
                t[o[i]] = f[i];
}

static Lock nseclk;
static Lock fdlk;
static int fd = -1;
static struct {
        int     pid;
        int     fd;
} fds[64];

vlong
nsec(void)
{
        uchar b[8];
        vlong t;
        int pid, i, *f, tries;

        /*
         * Threaded programs may have multiple procs
         * with different fd tables, so we may need to open
         * /dev/bintime on a per-pid basis
         */
        pid = _tos->pid;
        f = nil;
        for(i = 0; i < nelem(fds); i++)
                if(fds[i].pid == pid){
                        f = &fds[i].fd;
                        break;
                }
        if(i == nelem(fds)){
                lock(&nseclk);
                for(i = 0; i < nelem(fds); i++)
                        if(fds[i].pid == 0){
                                fds[i].pid = pid;
                                fds[i].fd = -1;
                                f = &fds[i].fd;
                                break;
                        }
                unlock(&nseclk);
        }
        if(f == nil)
                f = &fd;
        for(tries = 0; tries < 2; tries++){
                if(*f < 0){
                        if(f == &fd)
                                lock(&fdlk);
                        if((*f = open("/dev/bintime", OREAD|OCEXEC)) < 0)
                                break;
                        fd = *f;
                        if(f == &fd)
                                unlock(&fdlk);
                }
                if(pread(*f, b, sizeof b, 0) == sizeof b){
                        be2vlong(&t, b);
                        return t;
                }
                close(*f);
                *f = -1;
        }
        if(i < nelem(fds))
                fds[i].pid = 0; /* unlocked release */
        return 0;
}

Reply via email to