i've been having trouble with nsec. i've been dealing with an application that has ~128 processes. it does not use the thread library, but these processes all share memory. unfortunately, this results in wild thrashing of nsec(2) because there are more shared-memory processes than slots in the fds[] table in /sys/src/libc/nsec.c. a call to nsec can cause delays of up to 1s.
unfortunately, this isn't the real motivation. the real motivation is that recently a few processes were added that need to have their own fd tables. and unfortunately this causes nsec() to enter an infinite loop. in looking at the code, there seemed to be a number of ways to fix one particular problem, but the given algorithm seems resistant to a generally correct solution. it seemed to me that the _privates (see exec(2)) array was the way to go. process-private memory will never by falsely shared between processes that don't share fd tables. i kept the global fd to keep from opening nsec() too many times. in the case of this application, instead of opening nsec() afresh on nearly every call, it is now opened just 3 times. one note is that while i'm aware of privalloc(2), i didn't use it. the implementation doesn't appear correct for shared-memory procs. i think there are two issues - locking is unnecessary. the only preemptable unit of execution is a process and each process is guarenteed to have its own instance of _privates and _nprivates. - for shared-memory procs, we will run out of privates because the static privinit will be falsely shared. privinit should be replaced by using a private entry. i've attached my proposed solution. - erik ---- #include <u.h> #include <libc.h> extern void **_privates; extern int _nprivates; int fd = -1; /* * BUG: this is chosen by fiat and without coordination. * privalloc(2) does not appear safe in a shared-memory * environment. */ #define Fd ((int*)_privates[0]) 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 int* getfd(void) { if(Fd != nil) return Fd; return &fd; } static void reopen(int *fd) { *fd = open("/dev/bintime", OREAD|OCEXEC); } vlong nsec(void) { int *p; uchar b[8]; vlong t; p = getfd(); if(*p == -1) reopen(p); if(pread(*p, b, sizeof b, 0) != sizeof b){ if(p != Fd){ p = malloc(sizeof *p); if(p == nil) return 0; _privates[0] = p; } reopen(p); if(pread(*p, b, sizeof b, 0) != sizeof b) return 0; } be2vlong(&t, b); return t; }