git: 9front

Download patch

ref: 31c1b7bf798078fbd0217a8f3118e03808eca014
parent: d82eb33aeb3c31456e13a3299d375b965e5e1744
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri May 23 14:56:20 EDT 2014

libc: avoid static table and supurious reads in nsec()

use two per process memory slots, one for the
pid and one for the fd instead of a global table
avoiding the case when the table gets full.

instead of calling pread() on the cached fd
(dangerous as it has side effects when the
fd was not closed), we check if the cached fd
is still good  using fd2path() when called
the first time in this process.

--- a/sys/src/libc/9sys/nsec.c
+++ b/sys/src/libc/9sys/nsec.c
@@ -16,60 +16,48 @@
 		t[o[i]] = f[i];
 }
 
-static int fd = -1;
-static struct {
-	int	pid;
-	int	fd;
-} fds[64];
+static int
+stillopen(int fd, char *name)
+{
+	char buf[64];
 
+	return fd >= 0 && fd2path(fd, buf, sizeof(buf)) == 0 && strcmp(buf, name) == 0;
+}
+
 vlong
 nsec(void)
 {
+	static char name[] = "/dev/bintime";
+	static int *pidp = nil, *fdp = nil, fd = -1;
 	uchar b[8];
 	vlong t;
-	int pid, i, f, tries;
+	int f;
 
-	/*
-	 * Threaded programs may have multiple procs
-	 * with different fd tables, so we may need to open
-	 * /dev/bintime on a per-pid basis
-	 */
-
-	/* First, look if we've opened it for this particular pid */
-	pid = _tos->pid;
-	do{
-		f = -1;
-		for(i = 0; i < nelem(fds); i++)
-			if(fds[i].pid == pid){
-				f = fds[i].fd;
-				break;
-			}
-		tries = 0;
-		if(f < 0){
-			/* If it's not open for this pid, try the global pid */
-			if(fd >= 0)
-				f = fd;
-			else{
-				/* must open */
-				if((f = open("/dev/bintime", OREAD|OCEXEC)) < 0)
-					return 0;
-				fd = f;
-				for(i = 0; i < nelem(fds); i++)
-					if(fds[i].pid == pid || fds[i].pid == 0){
-						fds[i].pid = pid;
-						fds[i].fd = f;
-						break;
-					}
-			}
+	if(pidp != nil && *pidp == _tos->pid)
+		f = *fdp;
+	else{
+Reopen:
+		f = fd;
+		if(fdp != nil && *fdp != f && stillopen(*fdp, name))
+			f = *fdp;
+		else if(!stillopen(f, name)){
+			if((f = open(name, OREAD|OCEXEC)) < 0)
+				return 0;
 		}
-		if(pread(f, b, sizeof b, 0) == sizeof b){
-			be2vlong(&t, b);
-			return t;
+		fd = f;
+		if(fdp == nil){
+			fdp = (int*)privalloc();
+			pidp = (int*)privalloc();
 		}
+		*fdp = f;
+		*pidp = _tos->pid;
+	}
+	if(pread(f, b, sizeof b, 0) != sizeof b){
+		if(!stillopen(f, name))
+			goto Reopen;
 		close(f);
-		if(i < nelem(fds))
-			fds[i].fd = -1;
-	}while(tries++ == 0);	/* retry once */
-	USED(tries);
-	return 0;
+		return 0;
+	}
+	be2vlong(&t, b);
+	return t;
 }
--- a/sys/src/libc/9sys/time.c
+++ b/sys/src/libc/9sys/time.c
@@ -1,42 +1,6 @@
 #include <u.h>
 #include <libc.h>
 
-
-/*
- *  After a fork with fd's copied, both fd's are pointing to
- *  the same Chan structure.  Since the offset is kept in the Chan
- *  structure, the seek's and read's in the two processes can
- *  compete at moving the offset around.  Hence the unusual loop
- *  in the middle of this routine.
- */
-static long
-oldtime(long *tp)
-{
-	char b[20];
-	static int f = -1;
-	int i, retries;
-	long t;
-
-	memset(b, 0, sizeof(b));
-	for(retries = 0; retries < 100; retries++){
-		if(f < 0)
-			f = open("/dev/time", OREAD|OCEXEC);
-		if(f < 0)
-			break;
-		if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){
-			close(f);
-			f = -1;
-		} else {
-			if(i != 0)
-				break;
-		}
-	}
-	t = atol(b);
-	if(tp)
-		*tp = t;
-	return t;
-}
-
 long
 time(long *tp)
 {
@@ -43,8 +7,6 @@
 	vlong t;
 
 	t = nsec()/1000000000LL;
-	if(t == 0)
-		t = oldtime(0);
 	if(tp != nil)
 		*tp = t;
 	return t;
--