here's an improved version.  the previous version had a problem when
shared memory but not shared fd in this situation
        p0:
                nsec()  -> fd 3
                ...
        p1:
                open()  -> fd 3
                nsec()  -> fail

one potential modification is to ditch the malloc and allocate
two privalloc entries.

one interesting bit that is not documented in the privalloc(2) man
page is that privalloc() allocations are shared and inherited when
a process forks, but the memory spaces are not.  thus a privalloc
for each new pid would be an error.

it would require a modification to kexit() to change this.  but it might
make sense, because sharing privalloc entries seems exactly the
opposite of what privalloc is supposed to be doing.

- erik

---

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

typedef struct  Nfd     Nfd;
struct Nfd {
        int     pid;
        int     fd;
};

static  void    **nsecpriv;
#define Fd      ((Nfd*)nsecpriv[0])


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 Nfd*
getfd(void)
{
        Nfd *p;

        if(nsecpriv != nil && Fd->pid == _tos->pid)
                return Fd;
        if(nsecpriv == nil){
                /*
                 * privalloc's allocates slots on a shared
                 * basis, even though the memory slots
                 * themselves are proc-private.
                 */
                nsecpriv = privalloc();
                if(nsecpriv == nil)
                        return nil;
                *nsecpriv = p = malloc(sizeof *p);
                if(p == nil)
                        return nil;
        }else
                p = *nsecpriv;
        p->fd = -1;
        return p;
}

vlong
nsec(void)
{
        uchar b[8];
        vlong t;
        Nfd *p;

        if((p = getfd()) == nil)
                return 0;
        if(p->fd == -1){
                p->fd = open("/dev/bintime", OREAD|OCEXEC);
                p->pid = _tos->pid;
        }
        if(pread(p->fd, b, sizeof b, 0) == sizeof b){
                be2vlong(&t, b);
                return t;
        }
        return 0;
}

Reply via email to