> 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*)ℴ
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;
}