9front - general discussion about 9front
 help / color / mirror / Atom feed
From: bsdsm@sdf.org
To: 9front@9front.org
Subject: [9front] Re: [Patch] APE changes (2019 Lufia patches)
Date: Fri, 26 Feb 2021 19:23:00 -0000	[thread overview]
Message-ID: <5591aeb1a24fac8a3e472085c5be336c.squirrel@mx.sdf.org> (raw)
In-Reply-To: <0e170f2c1818fb21b795c2151e52adaf.squirrel@mx.sdf.org>

[-- Attachment #1: Type: text/plain, Size: 996 bytes --]


Sorry for the delay. Attached are the changes, minus architecture
specific code, with interests separated as previously discussed.

Please allow me a moment to address my intentions. My goals are more
human than software related. I began working on a port of Lufia's
changes not long after the pull requests. I stopped for some of the
reasons already discussed: git9, libressl isn't desired, etc. I
decided to put something together only after finding out that those
original patches are still in limbo after two years through 9fans. My
intention being that if even a single line presented was thought
worthy of import then I could reach out to Lufia and say, 'hey check
this out, and maybe your next patch can come straight to 9front.'

Perhaps my goals were misguided. It is not my intention to denigrate
anyone, 9fan or otherwise.

As a final note I agree with the comments made previously about
nitpicking the changes. Please nitpick everything. I just wanted to
make my intentions clearer.

[-- Attachment #2.1: Type: text/plain, Size: 332 bytes --]

from postmaster@1ess:
The following attachment had content that we can't
prove to be harmless.  To avoid possible automatic
execution, we changed the content headers.
The original header was:

	Content-Type: text/x-patch; name="pthread.diff"
	Content-Transfer-Encoding: 8bit
	Content-Disposition: attachment; filename="pthread.diff"

[-- Attachment #2.2: pthread.diff.suspect --]
[-- Type: application/octet-stream, Size: 25669 bytes --]

diff -r bfe93397b157 sys/include/ape/pthread.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/include/ape/pthread.h	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,105 @@
+#ifndef __PTHREAD_H
+#define __PTHREAD_H
+#pragma lib "/$M/lib/ape/libpthread.a"
+
+#define _LOCK_EXTENSION
+#define _QLOCK_EXTENSION
+#include <sys/types.h>
+#include <unistd.h>
+#include <lock.h>
+#include <qlock.h>
+
+typedef struct pthread_once pthread_once_t;
+typedef pid_t pthread_t;
+typedef int pthread_attr_t;
+typedef struct pthread_mutex pthread_mutex_t;
+typedef int pthread_mutexattr_t;
+typedef struct pthread_cond pthread_cond_t;
+typedef int pthread_condattr_t;
+typedef struct pthread_key pthread_key_t;
+
+enum {
+	PTHREAD_THREADS_MAX = 1000,
+
+	PTHREAD_CANCEL_DISABLE = 1,
+};
+
+struct pthread_once {
+	Lock l;
+	int once;
+};
+struct pthread_mutex {
+	QLock l;
+
+	Lock mu;
+	pthread_t pid;
+	int ref;
+	pthread_mutexattr_t attr;
+};
+struct pthread_cond {
+	QLock l;
+	Rendez r;
+};
+struct pthread_key {
+	Lock l;
+	void (*destroy)(void*);
+	struct {
+		pthread_t	pid;
+		const void	*p;
+	} *arenas;
+	int n;
+};
+
+#define PTHREAD_ONCE_INIT		{ 0 }
+#define PTHREAD_MUTEX_INITIALIZER	{ 0 }
+#define PTHREAD_MUTEX_DEFAULT		0
+#define PTHREAD_MUTEX_NORAML		1
+#define PTHREAD_MUTEX_RECURSIVE	2
+#define PTHREAD_COND_INITIALIZER	{ 0 }
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int	pthread_atfork(void (*)(void), void (*)(void), void (*)(void));
+extern int	pthread_once(pthread_once_t*, void (*)(void));
+extern pthread_t	pthread_self(void);
+extern int	pthread_equal(pthread_t, pthread_t);
+extern int	pthread_create(pthread_t*, pthread_attr_t*, void *(*)(void*), void*);
+extern void	pthread_exit(void*);
+extern int	pthread_join(pthread_t, void**);
+
+extern int	pthread_mutexattr_init(pthread_mutexattr_t*);
+extern int	pthread_mutexattr_destroy(pthread_mutexattr_t*);
+extern int	pthread_mutexattr_settype(pthread_mutexattr_t*, int);
+
+extern int	pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*);
+extern int	pthread_mutex_lock(pthread_mutex_t*);
+extern int	pthread_mutex_unlock(pthread_mutex_t*);
+extern int	pthread_mutex_trylock(pthread_mutex_t*);
+extern int	pthread_mutex_destroy(pthread_mutex_t*);
+
+extern int	pthread_cond_init(pthread_cond_t*, pthread_condattr_t*);
+extern int	pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*);
+extern int	pthread_cond_signal(pthread_cond_t*);
+extern int	pthread_cond_broadcast(pthread_cond_t*);
+extern int	pthread_cond_destroy(pthread_cond_t*);
+
+extern int	pthread_key_create(pthread_key_t*, void (*)(void*));
+extern int	pthread_key_delete(pthread_key_t);
+extern void	*pthread_getspecific(pthread_key_t);
+extern int	pthread_setspecific(pthread_key_t, const void*);
+
+extern int	pthread_setcancelstate(int, int*);
+
+#ifndef _PTHREAD_SIGMASK
+#define _PTHREAD_SIGMASK
+#include <signal.h>
+extern int	pthread_sigmask(int, const sigset_t*, sigset_t*);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r bfe93397b157 sys/include/ape/qlock.h
--- a/sys/include/ape/qlock.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/qlock.h	Fri Feb 12 10:59:32 2021 -0700
@@ -26,6 +26,14 @@
 	QLp 	*tail;
 } QLock;
 
+typedef
+struct Rendez
+{
+	QLock	*l;
+	QLp	*head;
+	QLp	*tail;
+} Rendez;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -34,6 +42,10 @@
 extern	void	qunlock(QLock*);
 extern	int	canqlock(QLock*);
 
+extern	void	rsleep(Rendez*);
+extern	int	rwakeup(Rendez*);
+extern	int	rwakeupall(Rendez*);
+
 #ifdef __cplusplus
 }
 #endif
diff -r 02e3059af5bc -r 5904c2b92376 sys/src/ape/lib/ap/plan9/qlock.c
--- a/sys/src/ape/lib/ap/plan9/qlock.c	Thu Feb 11 09:37:36 2021 +0100
+++ b/sys/src/ape/lib/ap/plan9/qlock.c	Thu Oct 26 02:42:26 2017 +0200
@@ -22,6 +22,9 @@
 enum
 {
 	Queuing,
+	QueuingR,
+	QueuingW,
+	Sleeping,
 };
 
 /* find a free shared memory location to queue ourselves in */
@@ -108,3 +112,254 @@
 	unlock(&q->lock);
 	return 0;
 }
+
+#if 0
+
+void
+rlock(RWLock *q)
+{
+	QLp *p, *mp;
+
+	lock(&q->lock);
+	if(q->writer == 0 && q->head == nil){
+		/* no writer, go for it */
+		q->readers++;
+		unlock(&q->lock);
+		return;
+	}
+
+	mp = getqlp();
+	p = q->tail;
+	if(p == 0)
+		q->head = mp;
+	else
+		p->next = mp;
+	q->tail = mp;
+	mp->next = nil;
+	mp->state = QueuingR;
+	unlock(&q->lock);
+
+	/* wait in kernel */
+	while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
+		;
+	mp->inuse = 0;
+}
+
+int
+canrlock(RWLock *q)
+{
+	lock(&q->lock);
+	if (q->writer == 0 && q->head == nil) {
+		/* no writer; go for it */
+		q->readers++;
+		unlock(&q->lock);
+		return 1;
+	}
+	unlock(&q->lock);
+	return 0;
+}
+
+void
+runlock(RWLock *q)
+{
+	QLp *p;
+
+	lock(&q->lock);
+	if(q->readers <= 0)
+		abort();
+	p = q->head;
+	if(--(q->readers) > 0 || p == nil){
+		unlock(&q->lock);
+		return;
+	}
+
+	/* start waiting writer */
+	if(p->state != QueuingW)
+		abort();
+	q->head = p->next;
+	if(q->head == 0)
+		q->tail = 0;
+	q->writer = 1;
+	unlock(&q->lock);
+
+	/* wakeup waiter */
+	while((*_rendezvousp)(p, (void*)0) == (void*)~0)
+		;
+}
+
+void
+wlock(RWLock *q)
+{
+	QLp *p, *mp;
+
+	lock(&q->lock);
+	if(q->readers == 0 && q->writer == 0){
+		/* noone waiting, go for it */
+		q->writer = 1;
+		unlock(&q->lock);
+		return;
+	}
+
+	/* wait */
+	p = q->tail;
+	mp = getqlp();
+	if(p == nil)
+		q->head = mp;
+	else
+		p->next = mp;
+	q->tail = mp;
+	mp->next = nil;
+	mp->state = QueuingW;
+	unlock(&q->lock);
+
+	/* wait in kernel */
+	while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
+		;
+	mp->inuse = 0;
+}
+
+int
+canwlock(RWLock *q)
+{
+	lock(&q->lock);
+	if (q->readers == 0 && q->writer == 0) {
+		/* no one waiting; go for it */
+		q->writer = 1;
+		unlock(&q->lock);
+		return 1;
+	}
+	unlock(&q->lock);
+	return 0;
+}
+
+void
+wunlock(RWLock *q)
+{
+	QLp *p;
+
+	lock(&q->lock);
+	if(q->writer == 0)
+		abort();
+	p = q->head;
+	if(p == nil){
+		q->writer = 0;
+		unlock(&q->lock);
+		return;
+	}
+	if(p->state == QueuingW){
+		/* start waiting writer */
+		q->head = p->next;
+		if(q->head == nil)
+			q->tail = nil;
+		unlock(&q->lock);
+		while((*_rendezvousp)(p, (void*)0) == (void*)~0)
+			;
+		return;
+	}
+
+	if(p->state != QueuingR)
+		abort();
+
+	/* wake waiting readers */
+	while(q->head != nil && q->head->state == QueuingR){
+		p = q->head;
+		q->head = p->next;
+		q->readers++;
+		while((*_rendezvousp)(p, (void*)0) == (void*)~0)
+			;
+	}
+	if(q->head == nil)
+		q->tail = nil;
+	q->writer = 0;
+	unlock(&q->lock);
+}
+
+void
+rsleep(Rendez *r)
+{
+	QLp *t, *me;
+
+	if(!r->l)
+		abort();
+	lock(&r->l->lock);
+	/* we should hold the qlock */
+	if(!r->l->locked)
+		abort();
+
+	/* add ourselves to the wait list */
+	me = getqlp();
+	me->state = Sleeping;
+	if(r->head == nil)
+		r->head = me;
+	else
+		r->tail->next = me;
+	me->next = nil;
+	r->tail = me;
+
+	/* pass the qlock to the next guy */
+	t = r->l->head;
+	if(t){
+		r->l->head = t->next;
+		if(r->l->head == nil)
+			r->l->tail = nil;
+		unlock(&r->l->lock);
+		while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0)
+			;
+	}else{
+		r->l->locked = 0;
+		unlock(&r->l->lock);
+	}
+
+	/* wait for a wakeup */
+	while((*_rendezvousp)(me, (void*)1) == (void*)~0)
+		;
+	me->inuse = 0;
+}
+
+int
+rwakeup(Rendez *r)
+{
+	QLp *t;
+
+	/*
+	 * take off wait and put on front of queue
+	 * put on front so guys that have been waiting will not get starved
+	 */
+	
+	if(!r->l)
+		abort();
+	lock(&r->l->lock);
+	if(!r->l->locked)
+		abort();
+
+	t = r->head;
+	if(t == nil){
+		unlock(&r->l->lock);
+		return 0;
+	}
+
+	r->head = t->next;
+	if(r->head == nil)
+		r->tail = nil;
+
+	t->next = r->l->head;
+	r->l->head = t;
+	if(r->l->tail == nil)
+		r->l->tail = t;
+
+	t->state = Queuing;
+	unlock(&r->l->lock);
+	return 1;
+}
+
+int
+rwakeupall(Rendez *r)
+{
+	int i;
+
+	for(i=0; rwakeup(r); i++)
+		;
+	return i;
+}
+
+#endif
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/fork.c
--- a/sys/src/ape/lib/ap/plan9/fork.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/plan9/fork.c	Fri Feb 12 10:59:32 2021 -0700
@@ -2,18 +2,58 @@
 #include <errno.h>
 #include <unistd.h>
 #include "sys9.h"
+#include <pthread.h>
+
+enum {
+	NHANDLERS = 100
+};
+
+static void (*preparehdlr[NHANDLERS])(void);
+static void (*parenthdlr[NHANDLERS])(void);
+static void (*childhdlr[NHANDLERS])(void);
+static int nprepare;
+static int nparent;
+static int nchild;
+
+int
+pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
+{
+	if(prepare != NULL){
+		if(nprepare >= NHANDLERS)
+			return ENOMEM;
+		preparehdlr[nprepare++] = prepare;
+	}
+	if(parent != NULL){
+		if(nparent >= NHANDLERS)
+			return ENOMEM;
+		parenthdlr[nparent++] = parent;
+	}
+	if(child != NULL){
+		if(nchild >= NHANDLERS)
+			return ENOMEM;
+		childhdlr[nchild++] = child;
+	}
+	return 0;
+}
 
 pid_t
 fork(void)
 {
-	int n;
+	int n, i;
 
+	for(i = nprepare-1; i >= 0; i--)
+		preparehdlr[i]();
 	n = _RFORK(RFENVG|RFFDG|RFPROC);
 	if(n < 0)
 		_syserrno();
 	if(n == 0) {
 		_detachbuf();
 		_sessleader = 0;
+		for(i = 0; i < nchild; i++)
+			childhdlr[i]();
+		return 0;
 	}
+	for(i = 0; i < nparent; i++)
+		parenthdlr[i]();
 	return n;
 }
diff -r bfe93397b157 sys/src/ape/lib/pthread/_pthread.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/_pthread.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,83 @@
+#include <pthread.h>
+#include <string.h>
+#include "lib.h"
+
+static Lock privlock;
+static Thread privileges[PTHREAD_THREADS_MAX];
+
+Thread *
+_pthreadalloc(void)
+{
+	Thread *p, *ep;
+
+	ep = privileges+nelem(privileges);
+	lock(&privlock);
+	for(p = privileges; p < ep; p++){
+		if(!p->inuse){
+			memset(p, 0, sizeof(*p));
+			p->inuse = 1;
+			unlock(&privlock);
+			return p;
+		}
+	}
+	unlock(&privlock);
+	return NULL;
+}
+
+void
+_pthreadsetpid(Thread *priv, pthread_t pid)
+{
+	lock(&privlock);
+	priv->pid = pid;
+	unlock(&privlock);
+}
+
+Thread *
+_pthreadnew(pthread_t pid)
+{
+	Thread *p, *ep, *freep = NULL;
+
+	ep = privileges+nelem(privileges);
+	lock(&privlock);
+	for(p = privileges; p < ep; p++){
+		if(p->inuse && p->pid == pid){
+			unlock(&privlock);
+			return p;
+		}
+		if(freep == NULL && !p->inuse)
+			freep = p;
+	}
+	if(freep == NULL){
+		unlock(&privlock);
+		return NULL;
+	}
+	memset(freep, 0, sizeof(*freep));
+	freep->inuse = 1;
+	freep->pid = pid;
+	unlock(&privlock);
+	return freep;
+}
+
+Thread *
+_pthreadget(pthread_t pid)
+{
+	Thread *p, *ep;
+
+	ep = privileges+nelem(privileges);
+	lock(&privlock);
+	for(p = privileges; p < ep; p++)
+		if(p->inuse && p->pid == pid){
+			unlock(&privlock);
+			return p;
+		}
+	unlock(&privlock);
+	return NULL;
+}
+
+void
+_pthreadfree(Thread *priv)
+{
+	lock(&privlock);
+	priv->inuse = 0;
+	unlock(&privlock);
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/cond_broadcast.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/cond_broadcast.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,10 @@
+#include <pthread.h>
+
+int
+pthread_cond_broadcast(pthread_cond_t *cond)
+{
+	qlock(cond->r.l);
+	rwakeupall(&cond->r);
+	qunlock(cond->r.l);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/cond_destroy.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/cond_destroy.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,8 @@
+#include <pthread.h>
+
+int
+pthread_cond_destroy(pthread_cond_t *)
+{
+	/* TODO: should we check cond is busy? */
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/cond_init.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/cond_init.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,10 @@
+#include <pthread.h>
+#include <string.h>
+
+int
+pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *)
+{
+	memset(cond, 0, sizeof(*cond));
+	cond->r.l = &cond->l;
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/cond_signal.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/cond_signal.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,10 @@
+#include <pthread.h>
+
+int
+pthread_cond_signal(pthread_cond_t *cond)
+{
+	qlock(cond->r.l);
+	rwakeup(&cond->r);
+	qunlock(cond->r.l);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/cond_wait.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/cond_wait.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,12 @@
+#include <pthread.h>
+
+int
+pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+	pthread_mutex_unlock(mutex);
+	qlock(cond->r.l);
+	rsleep(&cond->r);
+	qunlock(cond->r.l);
+	pthread_mutex_lock(mutex);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/create.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/create.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,37 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "lib.h"
+
+extern int	_RFORK(int);
+extern int	_RENDEZVOUS(unsigned long, unsigned long);
+
+int
+pthread_create(pthread_t *t, pthread_attr_t *attr, void *(*f)(void*), void *arg)
+{
+	void *p;
+	int pid;
+	Thread *priv;
+	unsigned long tag;
+
+	if(attr != NULL)
+		return EINVAL;
+	priv = _pthreadalloc();
+	if(priv == NULL)
+		return EAGAIN;
+	tag = (unsigned long)priv;
+	pid = _RFORK(RFFDG|RFPROC|RFMEM);
+	switch(pid){
+	case -1:
+		_syserrno();
+		unlock(&priv->l);
+		_pthreadfree(priv);
+		return errno;
+	case 0:
+		_RENDEZVOUS(tag, 0);
+		p = f(arg);
+		pthread_exit(p);
+		abort(); /* can't reach here */
+	}
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/equal.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/equal.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,7 @@
+#include <pthread.h>
+
+int
+pthread_equal(pthread_t t1, pthread_t t2)
+{
+	return t1 == t2;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/exit.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/exit.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,21 @@
+#include <pthread.h>
+#include <assert.h>
+#include "lib.h"
+
+extern void	_EXITS(char *);
+
+void
+pthread_exit(void *retval)
+{
+	Thread *priv;
+	pthread_t pid;
+
+	pid = pthread_self();
+	priv = _pthreadget(pid);
+	assert(priv != NULL);
+	lock(&priv->l);
+	priv->exited = 1;
+	priv->ret = retval;
+	unlock(&priv->l);
+	_EXITS(0);
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/getspecific.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/getspecific.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,21 @@
+#include <pthread.h>
+#include "lib.h"
+
+void *
+pthread_getspecific(pthread_key_t key)
+{
+	int i;
+	pthread_t pid;
+	const void *p;
+
+	pid = pthread_self();
+	lock(&key.l);
+	for(i = 0; i < key.n; i++)
+		if(key.arenas[i].pid == pid){
+			p = key.arenas[i].p;
+			unlock(&key.l);
+			return (void *)p;
+		}
+	unlock(&key.l);
+	return NULL;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/join.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/join.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,100 @@
+#define _RESEARCH_SOURCE
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <libv.h>
+#include "lib.h"
+
+typedef
+struct Waitmsg
+{
+	int	pid;	/* of loved one */
+	ulong	time[3];	/* of loved one & descendants */
+	char	*msg;
+} Waitmsg;
+
+extern int	_AWAIT(char*, int);
+
+static Waitmsg*
+_wait(void)
+{
+	int n, l;
+	char buf[512], *fld[5];
+	Waitmsg *w;
+
+	n = _AWAIT(buf, sizeof buf-1);
+	if(n < 0){
+		_syserrno();
+		return nil;
+	}
+	buf[n] = '\0';
+	if(getfields(buf, fld, nelem(fld)) != nelem(fld)){
+		errno = ENOBUFS;
+		return nil;
+	}
+	l = strlen(fld[4])+1;
+	w = malloc(sizeof(Waitmsg)+l);
+	if(w == nil)
+		return nil;
+	w->pid = atoi(fld[0]);
+	w->time[0] = atoi(fld[1]);
+	w->time[1] = atoi(fld[2]);
+	w->time[2] = atoi(fld[3]);
+	w->msg = (char*)&w[1];
+	memmove(w->msg, fld[4], l);
+	return w;
+}
+
+static void
+emitexits(void **ret, Thread *priv)
+{
+	if(ret == NULL){
+		return;
+	}
+	*ret = priv->ret;
+}
+
+int
+pthread_join(pthread_t t, void **ret)
+{
+	static Lock l;
+	Thread *priv;
+	int pid;
+	Waitmsg *msg;
+
+	lock(&l);
+	priv = _pthreadget(t);
+	if(priv == NULL){
+		unlock(&l);
+		return EINVAL;
+	}
+	lock(&priv->l);
+	if(priv->exited){
+		emitexits(ret, priv);
+		unlock(&priv->l);
+		_pthreadfree(priv);
+		unlock(&l);
+		return 0;
+	}
+	unlock(&priv->l);
+
+	while((msg=_wait()) != NULL){
+		pid = msg->pid;
+		free(msg);
+		if(pid == t)
+			break;
+	}
+	lock(&priv->l);
+	if(priv->exited){
+		emitexits(ret, priv);
+		unlock(&priv->l);
+		_pthreadfree(priv);
+		unlock(&l);
+		return 0;
+	}
+	unlock(&priv->l);
+	unlock(&l);
+	return ESRCH;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/key_create.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/key_create.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,20 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "lib.h"
+
+int
+pthread_key_create(pthread_key_t *key, void (*destr_func)(void*))
+{
+	if(destr_func)
+		return EINVAL; /* don't implement yet */
+	memset(key, 0, sizeof(*key));
+	key->destroy = destr_func;
+	key->n = 32;
+	key->arenas = malloc(sizeof(*key->arenas)*key->n);
+	if(key->arenas == NULL)
+		return ENOMEM;
+	memset(key->arenas, 0, sizeof(*key->arenas)*key->n);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/key_delete.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/key_delete.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,10 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include "lib.h"
+
+int
+pthread_key_delete(pthread_key_t key)
+{
+	free(key.arenas);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/lib.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/lib.h	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,48 @@
+#include <signal.h>
+
+#define nelem(a)	(sizeof(a)/sizeof((a)[0]))
+
+/* rfork */
+enum
+{
+	RFNAMEG		= (1<<0),
+	RFENVG		= (1<<1),
+	RFFDG		= (1<<2),
+	RFNOTEG		= (1<<3),
+	RFPROC		= (1<<4),
+	RFMEM		= (1<<5),
+	RFNOWAIT	= (1<<6),
+	RFCNAMEG	= (1<<10),
+	RFCENVG		= (1<<11),
+	RFCFDG		= (1<<12),
+	RFREND		= (1<<13),
+	RFNOMNT		= (1<<14)
+};
+
+typedef struct Thread Thread;
+struct Thread {
+	int		inuse;
+	pid_t		pid;
+
+	Lock		l;
+	int		exited;
+	void		*ret;
+	sigset_t	sigset;
+	int		state;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void	_syserrno(void);
+
+extern Thread*	_pthreadalloc(void);
+extern void	_pthreadsetpid(Thread*, pthread_t);
+extern Thread*	_pthreadnew(pthread_t);
+extern Thread*	_pthreadget(pthread_t);
+extern void	_pthreadfree(Thread*);
+
+#ifdef __cplusplus
+}
+#endif
diff -r bfe93397b157 sys/src/ape/lib/pthread/mkfile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mkfile	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,36 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libpthread.a
+OFILES=\
+	_pthread.$O\
+	cond_broadcast.$O\
+	cond_destroy.$O\
+	cond_init.$O\
+	cond_signal.$O\
+	cond_wait.$O\
+	create.$O\
+	equal.$O\
+	exit.$O\
+	getspecific.$O\
+	join.$O\
+	key_create.$O\
+	key_delete.$O\
+	mutexattr_destroy.$O\
+	mutexattr_init.$O\
+	mutexattr_settype.$O\
+	mutex_destroy.$O\
+	mutex_init.$O\
+	mutex_lock.$O\
+	mutex_trylock.$O\
+	mutex_unlock.$O\
+	once.$O\
+	self.$O\
+	setcancelstate.$O\
+	setspecific.$O\
+	sigmask.$O\
+
+HFILES=lib.h
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -FTVw -D_SUSV2_SOURCE -D_PLAN9_SOURCE
diff -r bfe93397b157 sys/src/ape/lib/pthread/mutex_destroy.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mutex_destroy.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,8 @@
+#include <pthread.h>
+
+int
+pthread_mutex_destroy(pthread_mutex_t *)
+{
+	/* TODO: should we check mutex is busy? */
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/mutex_init.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mutex_init.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,11 @@
+#include <pthread.h>
+#include <string.h>
+
+int
+pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
+{
+	memset(mutex, 0, sizeof(*mutex));
+	if(attr)
+		mutex->attr = *attr;
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/mutex_lock.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mutex_lock.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,23 @@
+#include <pthread.h>
+
+int
+pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+	pthread_t pid;
+
+	pid = pthread_self();
+	lock(&mutex->mu);
+	if(mutex->attr == PTHREAD_MUTEX_RECURSIVE && mutex->pid == pid){
+		mutex->ref++;
+		unlock(&mutex->mu);
+		return 0;
+	}
+	unlock(&mutex->mu);
+
+	qlock(&mutex->l);
+	lock(&mutex->mu);
+	mutex->pid = pid;
+	mutex->ref++;
+	unlock(&mutex->mu);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/mutex_trylock.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mutex_trylock.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,25 @@
+#include <pthread.h>
+#include <errno.h>
+
+int
+pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+	pthread_t pid;
+
+	pid = pthread_self();
+	lock(&mutex->mu);
+	if(mutex->attr == PTHREAD_MUTEX_RECURSIVE && mutex->pid == pid){
+		mutex->ref++;
+		unlock(&mutex->mu);
+		return 0;
+	}
+	unlock(&mutex->mu);
+
+	if(!canqlock(&mutex->l))
+		return EBUSY;
+	lock(&mutex->mu);
+	mutex->pid = pid;
+	mutex->ref++;
+	unlock(&mutex->mu);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/mutex_unlock.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mutex_unlock.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,29 @@
+#include <pthread.h>
+#include <errno.h>
+
+int
+pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+	pthread_t pid;
+
+	pid = pthread_self();
+	lock(&mutex->mu);
+	if(mutex->pid != pid){
+		unlock(&mutex->mu);
+		return EPERM;
+	}
+	if(mutex->attr == PTHREAD_MUTEX_RECURSIVE){
+		mutex->ref--;
+		if(mutex->ref <= 0){
+			mutex->pid = 0;
+			mutex->ref = 0;
+			qunlock(&mutex->l);
+		}
+		unlock(&mutex->mu);
+		return 0;
+	}
+	mutex->ref--;
+	qunlock(&mutex->l);
+	unlock(&mutex->mu);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/mutexattr_destroy.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mutexattr_destroy.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,7 @@
+#include <pthread.h>
+
+int
+pthread_mutexattr_destroy(pthread_mutexattr_t*)
+{
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/mutexattr_init.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mutexattr_init.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,8 @@
+#include <pthread.h>
+
+int
+pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+	*attr = 0;
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/mutexattr_settype.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/mutexattr_settype.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,8 @@
+#include <pthread.h>
+
+int
+pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
+{
+	*attr = kind;
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/once.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/once.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,13 @@
+#include <pthread.h>
+
+int
+pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
+{
+	lock(&once_control->l);
+	if(once_control->once == 0){
+		init_routine();
+		once_control->once++;
+	}
+	unlock(&once_control->l);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/self.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/self.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,8 @@
+#include <pthread.h>
+#include <unistd.h>
+
+pthread_t
+pthread_self(void)
+{
+	return getpid();
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/setcancelstate.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/setcancelstate.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,21 @@
+#include <pthread.h>
+#include <errno.h>
+#include "lib.h"
+
+int
+pthread_setcancelstate(int state, int *oldstate)
+{
+	Thread *priv;
+	pthread_t pid;
+
+	pid = pthread_self();
+	priv = _pthreadnew(pid);
+	if(priv == NULL)
+		return ENOMEM;
+	lock(&priv->l);
+	if(oldstate)
+		*oldstate = priv->state;
+	priv->state = state;
+	unlock(&priv->l);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/setspecific.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/setspecific.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,30 @@
+#include <pthread.h>
+#include <errno.h>
+#include "lib.h"
+
+int
+pthread_setspecific(pthread_key_t key, const void *p)
+{
+	int i;
+	pthread_t pid;
+
+	pid = pthread_self();
+	lock(&key.l);
+	/* exactly match */
+	for(i = 0; i < key.n; i++)
+		if(key.arenas[i].pid == pid){
+			key.arenas[i].p = p;
+			unlock(&key.l);
+			return 0;
+		}
+	/* unused */
+	for(i = 0; i < key.n; i++)
+		if(key.arenas[i].pid == 0){
+			key.arenas[i].pid = pid;
+			key.arenas[i].p = p;
+			unlock(&key.l);
+			return 0;
+		}
+	unlock(&key.l);
+	return ENOMEM;
+}
diff -r bfe93397b157 sys/src/ape/lib/pthread/sigmask.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/pthread/sigmask.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,21 @@
+#include <pthread.h>
+#include <errno.h>
+#include "lib.h"
+
+int
+pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
+{
+	Thread *priv;
+	pthread_t pid;
+
+	pid = pthread_self();
+	priv = _pthreadnew(pid);
+	if(priv == NULL)
+		return ENOMEM;
+	lock(&priv->l);
+	if(oldset)
+		*oldset = priv->sigset;
+	priv->sigset = *set;
+	unlock(&priv->l);
+	return 0;
+}

[-- Attachment #3.1: Type: text/plain, Size: 342 bytes --]

from postmaster@1ess:
The following attachment had content that we can't
prove to be harmless.  To avoid possible automatic
execution, we changed the content headers.
The original header was:

	Content-Type: text/x-patch; name="include_next.diff"
	Content-Transfer-Encoding: 8bit
	Content-Disposition: attachment; filename="include_next.diff"

[-- Attachment #3.2: include_next.diff.suspect --]
[-- Type: application/octet-stream, Size: 4046 bytes --]

diff -r bfe93397b157 sys/src/cmd/cpp/cpp.c
--- a/sys/src/cmd/cpp/cpp.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/cmd/cpp/cpp.c	Fri Feb 12 10:59:32 2021 -0700
@@ -238,7 +238,12 @@
 		break;
 
 	case KINCLUDE:
-		doinclude(trp);
+		doinclude(trp, 0);
+		trp->lp = trp->bp;
+		return;
+
+	case KINCLUDE_NEXT:
+		doinclude(trp, 1);
 		trp->lp = trp->bp;
 		return;
 
diff -r bfe93397b157 sys/src/cmd/cpp/cpp.h
--- a/sys/src/cmd/cpp/cpp.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/cmd/cpp/cpp.h	Fri Feb 12 10:59:32 2021 -0700
@@ -19,8 +19,8 @@
 		ASRSH, ASOR, ASAND, ELLIPS,
 		DSHARP1, NAME1, DEFINED, UMINUS, MAXTOK};
 
-enum kwtype { KIF, KIFDEF, KIFNDEF, KELIF, KELSE, KENDIF, KINCLUDE, KDEFINE,
-		KUNDEF, KLINE, KERROR, KWARNING, KPRAGMA, KDEFINED,
+enum kwtype { KIF, KIFDEF, KIFNDEF, KELIF, KELSE, KENDIF, KINCLUDE, KINCLUDE_NEXT,
+		KDEFINE, KUNDEF, KLINE, KERROR, KWARNING, KPRAGMA, KDEFINED,
 		KLINENO, KFILE, KDATE, KTIME, KSTDC, KEVAL };
 
 #define	ISDEFINED	01	/* has #defined value */
@@ -60,6 +60,7 @@
 	int	fd;		/* input source */
 	int	ifdepth;	/* conditional nesting in include */
 	struct	source *next;	/* stack for #include */
+	int	pos;		/* next position for #include_next */
 } Source;
 
 typedef struct nlist {
@@ -105,7 +106,7 @@
 void	control(Tokenrow *);
 void	dodefine(Tokenrow *);
 void	doadefine(Tokenrow *, int);
-void	doinclude(Tokenrow *);
+void	doinclude(Tokenrow *, int);
 void	doif(Tokenrow *, enum kwtype);
 void	expand(Tokenrow *, Nlist *);
 void	builtin(Tokenrow *, int);
diff -r bfe93397b157 sys/src/cmd/cpp/include.c
--- a/sys/src/cmd/cpp/include.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/cmd/cpp/include.c	Fri Feb 12 10:59:32 2021 -0700
@@ -6,12 +6,21 @@
 
 char	*objname;
 
+static int
+curpos(int next)
+{
+	if (next)
+		return cursource->pos;
+	return NINCLUDE;
+}
+
 void
-doinclude(Tokenrow *trp)
+doinclude(Tokenrow *trp, int next)
 {
 	char fname[256], iname[256], *p;
 	Includelist *ip;
-	int angled, len, fd, i;
+	Source *s;
+	int angled, len, fd, i, pos;
 
 	trp->tp += 1;
 	if (trp->tp>=trp->lp)
@@ -44,6 +53,7 @@
 	if (trp->tp < trp->lp || len==0)
 		goto syntax;
 	fname[len] = '\0';
+	pos = NINCLUDE;
 	if (fname[0]=='/') {
 		fd = open(fname, 0);
 		strcpy(iname, fname);
@@ -59,7 +69,7 @@
 				fd = open(iname, 0);
 			}
 		}
-		for (i=NINCLUDE-1; fd<0 && i>=0; i--) {
+		for (i=curpos(next)-1; fd<0 && i>=0; i--) {
 			ip = &includelist[i];
 			if (ip->file==NULL || ip->deleted || (angled && ip->always==0))
 				continue;
@@ -68,9 +78,12 @@
 			strcpy(iname, ip->file);
 			strcat(iname, "/");
 			strcat(iname, fname);
-			fd = open(iname, 0);
+			if((fd = open(iname, 0)) >= 0){
+				pos = i;
+				break;
+			}
 		}
-		if (fd<0 && angled) {
+		if (fd<0 && angled && !next) {
 			strcpy(iname, cursource->filename);
 			p = strrchr(iname, '/');
 			if(p != NULL) {
@@ -78,6 +91,7 @@
 				strcat(iname, "/");
 				strcat(iname, fname);
 				fd = open(iname, 0);
+				pos = NINCLUDE-1;
 			}
 		}
 	}
@@ -89,7 +103,8 @@
 	if (fd >= 0) {
 		if (++incdepth > 20)
 			error(FATAL, "#include too deeply nested");
-		setsource((char*)newstring((uchar*)iname, strlen(iname), 0), fd, NULL);
+		s = setsource((char*)newstring((uchar*)iname, strlen(iname), 0), fd, NULL);
+		s->pos = pos;
 		genline();
 	} else {
 		trp->tp = trp->bp+2;
diff -r bfe93397b157 sys/src/cmd/cpp/lex.c
--- a/sys/src/cmd/cpp/lex.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/cmd/cpp/lex.c	Fri Feb 12 10:59:32 2021 -0700
@@ -538,6 +538,7 @@
 	s->inp = s->inb;
 	s->inl = s->inp+len;
 	s->inl[0] = s->inl[1] = s->inl[2] = s->inl[3] = EOFC;
+	s->pos = NINCLUDE; /* outside of include dirs */
 	return s;
 }
 
diff -r bfe93397b157 sys/src/cmd/cpp/nlist.c
--- a/sys/src/cmd/cpp/nlist.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/cmd/cpp/nlist.c	Fri Feb 12 10:59:32 2021 -0700
@@ -28,6 +28,7 @@
 	"else",		KELSE,		ISKW,
 	"endif",	KENDIF,		ISKW,
 	"include",	KINCLUDE,	ISKW,
+	"include_next",	KINCLUDE_NEXT,	ISKW,	// extension to ANSI
 	"define",	KDEFINE,	ISKW,
 	"undef",	KUNDEF,		ISKW,
 	"line",		KLINE,		ISKW,

[-- Attachment #4.1: Type: text/plain, Size: 348 bytes --]

from postmaster@1ess:
The following attachment had content that we can't
prove to be harmless.  To avoid possible automatic
execution, we changed the content headers.
The original header was:

	Content-Type: text/x-patch; name="excluded_middle.diff"
	Content-Transfer-Encoding: 8bit
	Content-Disposition: attachment; filename="excluded_middle.diff"

[-- Attachment #4.2: excluded_middle.diff.suspect --]
[-- Type: application/octet-stream, Size: 29223 bytes --]

diff -r bfe93397b157 sys/include/ape/bsd.h
--- a/sys/include/ape/bsd.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/bsd.h	Fri Feb 12 10:59:32 2021 -0700
@@ -36,6 +36,12 @@
 extern int	rcmd(char**, int, char*, char*, char*, int*);
 extern int	strcasecmp(char*, char*);
 extern int	strncasecmp(char*, char*,int);
+extern unsigned int	arc4random(void);
+extern void	arc4random_buf(void*, size_t);
+extern int	getentropy(void*, size_t);
+
+extern const char*	getprogname(void);
+extern void	setprogname(const char*);
 
 extern int	getopt(int, char**, char*);
 extern int	opterr;
@@ -44,9 +50,9 @@
 extern char	*optarg;
 extern char	*mktemp(char *);
 extern char	*sys_errlist[];
-extern int		sys_nerr;
+extern int	sys_nerr;
 
-extern int	gethostname(char*, int);
+extern int	gethostname(char*, size_t);
 
 #ifdef __cplusplus
 }
diff -r bfe93397b157 sys/include/ape/errno.h
--- a/sys/include/ape/errno.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/errno.h	Fri Feb 12 10:59:32 2021 -0700
@@ -80,6 +80,16 @@
 #define ECANCELED	61
 #define EINPROGRESS	62
 
+/* from research unix */
+#define ETXTBSY	63
+
+/* Added in more recent 1003.x versions */
+#define EALREADY	64
+#define ECONNRESET	65
+
+#define EOVERFLOW	66
+#define ELOOP		67
+
 #endif /* _POSIX_SOURCE */
 
 #endif /* __ERRNO */
diff -r bfe93397b157 sys/include/ape/inttypes.h
--- a/sys/include/ape/inttypes.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/inttypes.h	Fri Feb 12 10:59:32 2021 -0700
@@ -11,21 +11,25 @@
 #define PRId16 "d"
 #define PRId32 "d"
 #define PRId64 "lld"
+#define PRIdMAX "lld"
 
 #define PRIo8 "o"
 #define PRIo16 "o"
 #define PRIo32 "o"
 #define PRIo64 "llo"
+#define PRIoMAX "llo"
 
 #define PRIx8 "x"
 #define PRIx16 "x"
 #define PRIx32 "x"
 #define PRIx64 "llx"
+#define PRIxMAX "llx"
 
 #define PRIu8 "u"
 #define PRIu16 "u"
 #define PRIu32 "u"
 #define PRIu64 "llu"
+#define PRIuMAX "llu"
 
 extern intmax_t strtoimax(const char *, char **, int);
 
diff -r bfe93397b157 sys/include/ape/lib9.h
--- a/sys/include/ape/lib9.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/lib9.h	Fri Feb 12 10:59:32 2021 -0700
@@ -75,5 +75,6 @@
 extern	void		setfcr(unsigned long);
 extern	void		setfsr(unsigned long);
 extern	int 	fd2path(int, char*, int);
+extern	vlong		nsec(void);
 
 #endif
diff -r bfe93397b157 sys/include/ape/libgen.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/include/ape/libgen.h	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,16 @@
+#ifndef __LIBGEN_H
+#define __LIBGEN_H
+#pragma lib "/$M/lib/ape/libap.a"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *dirname(char *path);
+extern char *basename(char *path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r bfe93397b157 sys/include/ape/netdb.h
--- a/sys/include/ape/netdb.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/netdb.h	Fri Feb 12 10:59:32 2021 -0700
@@ -147,6 +147,8 @@
 #define NI_NUMERICSCOPE	0x0010	/* For IPv6 addresses, the numeric form of the scope identifier is returned
 				   instead of its name. */
 #define NI_DGRAM	0x0020	/* Indicates that the service is a datagram service (SOCK_DGRAM). */
+#define NI_MAXHOST	1025
+#define NI_MAXSERV	32
 
 /* Error values for `getaddrinfo' and `getnameinfo' functions.  */
 #define EAI_BADFLAGS	  -1	/* Invalid value for `ai_flags' field */
diff -r bfe93397b157 sys/include/ape/poll.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/include/ape/poll.h	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,41 @@
+#ifndef __POLL_H
+#define __POLL_H
+#pragma lib "/$M/lib/ape/libap.a"
+
+#ifndef	FD_SETSIZE
+#define	FD_SETSIZE	96
+#endif
+
+struct pollfd {
+	int fd;			/* file descriptor */
+	short events;	/* events to look for */
+	short revents;	/* events returned */
+};
+
+typedef unsigned long nfds_t;
+
+#define	POLLIN		0x001
+#define	POLLPRI		0x002
+#define	POLLOUT		0x004
+#define	POLLERR		0x008
+#define	POLLHUP		0x010
+#define	POLLNVAL	0x020
+
+#define	POLLRDNORM	0x040
+#define	POLLRDBAND	0x080
+#define	POLLWRNORM	POLLOUT
+#define	POLLWRBAND	0x100
+
+#define	INFTIM	-1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int poll(struct pollfd fds[], nfds_t nfds, int timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r bfe93397b157 sys/include/ape/signal.h
--- a/sys/include/ape/signal.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/signal.h	Fri Feb 12 10:59:32 2021 -0700
@@ -37,11 +37,12 @@
 #define SIGTSTP	18	/* interactive stop */
 #define SIGTTIN	19	/* read from ctl tty by member of background */
 #define SIGTTOU	20	/* write to ctl tty by member of background */
-#define SIGVTALRM 21 /* virtual alarm clock */
-#define SIGPROF 22  /* profiling alarm clock */
+#define SIGWINCH 21	/* window size changes */
+#define SIGVTALRM 22 /* virtual alarm clock */
+#define SIGPROF 23  /* profiling alarm clock */
 
 #ifdef _BSD_EXTENSION
-#define NSIG 23
+#define NSIG 24
 #endif
 
 #ifdef __cplusplus
@@ -65,6 +66,10 @@
 };
 /* values for sa_flags */
 #define SA_NOCLDSTOP	1
+#define SA_ONSTACK	2
+#define SA_RESETHAND	3
+#define SA_RESTART	4
+#define SA_RESTORER	5
 
 /* first argument to sigprocmask */
 #define SIG_BLOCK	1
diff -r bfe93397b157 sys/include/ape/stdint.h
--- a/sys/include/ape/stdint.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/stdint.h	Fri Feb 12 10:59:32 2021 -0700
@@ -10,6 +10,15 @@
 typedef unsigned int _uintptr_t;
 #endif
 
+typedef char s8;
+typedef short s16;
+typedef long s32;
+typedef long long s64;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+typedef unsigned long long u64;
+
 typedef char int8_t;
 typedef short int16_t;
 typedef int int32_t;
diff -r bfe93397b157 sys/include/ape/stdlib.h
--- a/sys/include/ape/stdlib.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/stdlib.h	Fri Feb 12 10:59:32 2021 -0700
@@ -49,6 +49,10 @@
 extern size_t mbstowcs(wchar_t *, const char *, size_t);
 extern size_t wcstombs(char *, const wchar_t *, size_t);
 
+#ifdef _BSD_EXTENSION
+#include <bsd.h>
+#endif
+
 #ifdef _POSIX_C_SOURCE
 extern int mkstemp(char *template);
 #endif
diff -r bfe93397b157 sys/include/ape/sys/resource.h
--- a/sys/include/ape/sys/resource.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/sys/resource.h	Fri Feb 12 10:59:32 2021 -0700
@@ -5,6 +5,17 @@
     This header file is an extension to ANSI/POSIX
 #endif
 
+#include <sys/time.h>
+
+#pragma lib "/$M/lib/ape/libap.a"
+
+enum {
+	RUSAGE_SELF = 0,
+	RUSAGE_CHILDREN = -1
+};
+
+#define RUSAGE_SELF		RUSAGE_SELF
+#define RUSAGE_CHILDREN		RUSAGE_CHILDREN
 struct rusage {
 	struct timeval ru_utime;	/* user time used */
 	struct timeval ru_stime;	/* system time used */
@@ -26,4 +37,14 @@
 #define	ru_last		ru_nivcsw
 };
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int getrusage(int, struct rusage *);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* !__RESOURCE_H__ */
diff -r bfe93397b157 sys/include/ape/sys/socket.h
--- a/sys/include/ape/sys/socket.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/sys/socket.h	Fri Feb 12 10:59:32 2021 -0700
@@ -24,6 +24,7 @@
  */
 typedef int socklen_t;
 typedef unsigned short sa_family_t;
+typedef unsigned short in_port_t;
 
 /*
  * Types
@@ -178,6 +179,15 @@
 
 #define	MSG_MAXIOVLEN	16
 
+#define TCP_NODELAY	1
+#define TCP_MAXSEG	2
+
+enum {
+	SHUT_RD,		/* no more receptions */
+	SHUT_WR,		/* no more transmissions */
+	SHUT_RDWR,		/* no more receptions or transmissions */
+};
+
 extern int accept(int, void *, int *);
 extern int bind(int, void *, int);
 extern int connect(int, void *, int);
diff -r bfe93397b157 sys/include/ape/sys/stat.h
--- a/sys/include/ape/sys/stat.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/sys/stat.h	Fri Feb 12 10:59:32 2021 -0700
@@ -27,6 +27,7 @@
 #define	S__MASK		     0170000
 #ifdef _RESEARCH_SOURCE
 #define S_ISLNK(m)	(((m)&S__MASK) == 0120000)
+#define S_ISSOCK(m)	(((m)&S__MASK) == 0010000)
 #endif
 #define S_ISREG(m)	(((m)&S__MASK) == 0100000)
 #define S_ISDIR(m)	(((m)&S__MASK) == 0040000)
diff -r bfe93397b157 sys/include/ape/sys/types.h
--- a/sys/include/ape/sys/types.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/sys/types.h	Fri Feb 12 10:59:32 2021 -0700
@@ -2,6 +2,7 @@
 #define __TYPES_H
 
 #pragma lib "/$M/lib/ape/libap.a"
+
 typedef	unsigned short	ino_t;
 typedef	unsigned short	dev_t;
 typedef	long long		off_t;
@@ -10,6 +11,11 @@
 typedef short		gid_t;
 typedef short		nlink_t;
 typedef int		pid_t;
+typedef unsigned char	u_char;
+typedef unsigned short	u_short;
+typedef unsigned int	u_int;
+typedef unsigned long	u_long;
+typedef unsigned int	in_addr_t;
 
 #ifndef _SIZE_T
 #define _SIZE_T
@@ -25,6 +31,11 @@
 typedef long time_t;
 #endif
 
+#ifndef _CLOCKID_T
+#define _CLOCKID_T
+typedef int clockid_t;
+#endif
+
 #ifdef _BSD_EXTENSION
 #ifndef _CADDR_T
 #define _CADDR_T
diff -r bfe93397b157 sys/include/ape/syslog.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/include/ape/syslog.h	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,57 @@
+#ifndef __SYSLOG_H
+#define __SYSLOG_H
+#pragma lib "/$M/lib/ape/libap.a"
+
+enum {
+	/* facility */
+	LOG_KERN	= 0<<3,
+	LOG_USER	= 1<<3,
+	LOG_DAEMON	= 3<<3,
+	LOG_AUTH	= 4<<3,
+	LOG_SYSLOG	= 5<<3,
+	LOG_CRON	= 9<<3,
+	LOG_AUTHPRIV= 10<<3,
+	LOG_LOCAL0	= 16<<3,
+	LOG_LOCAL1	= 17<<3,
+	LOG_LOCAL2	= 18<<3,
+	LOG_LOCAL3	= 19<<3,
+	LOG_LOCAL4	= 20<<3,
+	LOG_LOCAL5	= 21<<3,
+	LOG_LOCAL6	= 22<<3,
+	LOG_LOCAL7	= 23<<3,
+};
+
+enum {
+	/* priority */
+	LOG_EMERG,
+	LOG_ALERT,
+	LOG_CRIT,
+	LOG_ERR,
+	LOG_WARNING,
+	LOG_NOTICE,
+	LOG_INFO,
+	LOG_DEBUG,
+};
+
+enum {
+	/* option */
+	LOG_PID		= 0x01,
+	LOG_CONS	= 0x02,
+	LOG_ODELAY	= 0x04,
+	LOG_NDELAY	= 0x08,
+	LOG_NOWAIT	= 0x10,
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void openlog(const char *, int, int);
+extern void syslog(int, const char *, ...);
+extern void closelog(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r bfe93397b157 sys/include/ape/time.h
--- a/sys/include/ape/time.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/time.h	Fri Feb 12 10:59:32 2021 -0700
@@ -9,6 +9,9 @@
 /* obsolsecent, but required */
 #define CLK_TCK CLOCKS_PER_SEC
 
+#define CLOCK_REALTIME 0
+#define CLOCK_MONOTONIC 1
+
 #ifndef _CLOCK_T
 #define _CLOCK_T
 typedef long clock_t;
@@ -17,6 +20,10 @@
 #define _TIME_T
 typedef long time_t;
 #endif
+#ifndef _CLOCKID_T
+#define _CLOCKID_T
+typedef int clockid_t;
+#endif
 
 struct tm {
 	int	tm_sec;
@@ -43,6 +50,8 @@
 extern struct tm *gmtime(const time_t *);
 extern struct tm *localtime(const time_t *);
 extern size_t strftime(char *, size_t, const char *, const struct tm *);
+extern int clock_gettime(clockid_t, struct timespec *);
+extern int clock_settime(clockid_t, struct timespec *);
 
 #ifdef _REENTRANT_SOURCE
 extern struct tm *gmtime_r(const time_t *, struct tm *);
diff -r bfe93397b157 sys/include/ape/unistd.h
--- a/sys/include/ape/unistd.h	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/include/ape/unistd.h	Fri Feb 12 10:59:32 2021 -0700
@@ -62,6 +62,7 @@
 #define	_SC_SAVED_IDS		9	/* saved suid/sgid per process */
 #define	_SC_VERSION		10	/* this version */
 #define _SC_LOGIN_NAME_MAX	11	/* max length of a login name */
+#define _SC_PAGESIZE		12
 
 /* pathconf argument */
 #define _PC_LINK_MAX		1
@@ -115,6 +116,7 @@
 extern int setgid(gid_t);
 extern int getgroups(int, gid_t *);
 extern pid_t getpgrp(void);
+extern int getpgid(pid_t);
 extern int setpgid(pid_t, pid_t);
 extern pid_t setsid(void);
 #endif
@@ -130,6 +132,7 @@
 extern int access(const char *, int);
 extern long pathconf(const char *, int);
 extern long fpathconf(int, int);
+extern int fchdir(int);
 #ifdef __TYPES_H
 extern int chown(const char *, uid_t, gid_t);
 #endif
@@ -144,6 +147,9 @@
 #ifdef __TYPES_H
 extern int ftruncate(int, off_t);
 extern off_t lseek(int, off_t, int);
+
+extern ssize_t pread(int, void *, size_t, off_t);
+extern ssize_t pwrite(int, const void *, size_t, off_t);
 #endif
 
 /* device- and class-specific functions */
@@ -159,8 +165,12 @@
 /* berkeley specific functions */
 #ifdef _BSD_EXTENSION
 #include <bsd.h>
+
+extern int getpagesize(void);
 #endif
 
+extern int gethostname(char *, size_t);
+
 #ifdef __cplusplus
 }
 #endif
diff -r bfe93397b157 sys/src/ape/lib/9/mkfile
--- a/sys/src/ape/lib/9/mkfile	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/9/mkfile	Fri Feb 12 10:59:32 2021 -0700
@@ -13,6 +13,7 @@
 	getfcr.$O\
 	getfields.$O\
 	mount.$O\
+	nsec.$O\
 	rendezvous.$O\
 	rfork.$O\
 	segattach.$O\
diff -r bfe93397b157 sys/src/ape/lib/9/nsec.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/9/nsec.c	Fri Feb 26 11:05:08 2021 -0700
@@ -0,0 +1,9 @@
+#include <lib9.h>
+
+extern vlong _NSEC(void);
+
+vlong
+nsec(void)
+{
+	return _NSEC();
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/clock_gettime.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/plan9/clock_gettime.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,33 @@
+#include <time.h>
+#include <sys/times.h>
+#include <lib9.h>
+#include <errno.h>
+
+#define NANO_IN_SEC 1000000000L
+
+int
+clock_gettime(clockid_t clock_id, struct timespec *tp)
+{
+	vlong ns;
+
+	switch(clock_id){
+	case CLOCK_REALTIME:
+	case CLOCK_MONOTONIC:
+		ns = nsec();
+		tp->tv_sec = ns/NANO_IN_SEC;
+		tp->tv_nsec = ns%NANO_IN_SEC;
+		return 0;
+	default:
+		errno = EINVAL;
+		return -1;
+	}
+}
+
+int
+clock_settime(clockid_t clock_id, struct timespec *tp)
+{
+	USED(clock_id);
+	USED(tp);
+	errno = EPERM;
+	return -1;
+}
diff -r 02e3059af5bc sys/src/ape/lib/ap/plan9/dirstat.c
--- a/sys/src/ape/lib/ap/plan9/dirstat.c	Thu Feb 11 09:37:36 2021 +0100
+++ b/sys/src/ape/lib/ap/plan9/dirstat.c	Fri Feb 12 10:59:32 2021 -0700
@@ -63,11 +63,11 @@
 
 	nd = DIRSIZE;
 	for(i=0; i<2; i++){	/* should work by the second try */
-		d = malloc(sizeof(Dir) + nd);
+		d = malloc(sizeof(Dir) + BIT16SZ +nd);
 		if(d == nil)
 			return nil;
 		buf = (uchar*)&d[1];
-		n = _FSTAT(fd, buf, nd);
+		n = _FSTAT(fd, buf, BIT16SZ+nd);
 		if(n < BIT16SZ){
 			free(d);
 			return nil;
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/fchdir.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/plan9/fchdir.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,32 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include "lib.h"
+#include <errno.h>
+
+extern int _FD2PATH(int fd, char *buf, int nbuf);
+extern int _CHDIR(char *dirname);
+
+int
+fchdir(int fd)
+{
+	char buf[_POSIX_PATH_MAX];
+	struct stat s;
+	int n;
+
+	if(fstat(fd, &s) < 0)
+		return -1;
+	if(!S_ISDIR(s.st_mode)){
+		errno = ENOTDIR;
+		return -1;
+	}
+
+	if (_FD2PATH(fd, buf, sizeof buf) < 0){
+		_syserrno();
+		return -1;
+	}
+	n = _CHDIR(buf);
+	if(n < 0)
+		_syserrno();
+	return n;
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/fsync.c
--- a/sys/src/ape/lib/ap/plan9/fsync.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/plan9/fsync.c	Fri Feb 12 10:59:32 2021 -0700
@@ -5,6 +5,6 @@
 int
 fsync(int)
 {
-	errno = EINVAL;
-	return -1;
+	/* TODO: should fsync return an error? */
+	return 0;
 }
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/getpgid.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/plan9/getpgid.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,31 @@
+#include "lib.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "sys9.h"
+
+int
+getpgid(pid_t pid)
+{
+	int n, f;
+	char buf[50], fname[30];
+
+	if(pid == 0)
+		pid = getpid();
+	sprintf(fname, "/proc/%d/noteid", pid);
+	f = open(fname, 0);
+	if(f < 0) {
+		errno = ESRCH;
+		return -1;
+	}
+	n = read(f, buf, sizeof(buf));
+	if(n < 0)
+		_syserrno();
+	else{
+		buf[n] = '\0';
+		n = atoi(buf);
+	}
+	close(f);
+	return n;
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/getrusage.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/plan9/getrusage.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,12 @@
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <string.h>
+
+int
+getrusage(int who, struct rusage *usage)
+{
+	/* dummy implementation */
+	USED(who);
+	memset(usage, 0, sizeof *usage);
+	return 0;
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/mkfile
--- a/sys/src/ape/lib/ap/plan9/mkfile	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/plan9/mkfile	Fri Feb 12 10:59:32 2021 -0700
@@ -25,6 +25,7 @@
 	chroot.$O\
 	chmod.$O\
 	chown.$O\
+	clock_gettime.$O\
 	close.$O\
 	convM2D.$O\
 	convD2M.$O\
@@ -42,6 +43,7 @@
 	execv.$O\
 	execve.$O\
 	execvp.$O\
+	fchdir.$O\
 	fcntl.$O\
 	fork.$O\
 	frexp.$O\
@@ -54,11 +56,13 @@
 	getgrnam.$O\
 	getgroups.$O\
 	getlogin.$O\
+	getpgid.$O\
 	getpgrp.$O\
 	getpid.$O\
 	getppid.$O\
 	getpwnam.$O\
 	getpwuid.$O\
+	getrusage.$O\
 	getuid.$O\
 	isatty.$O\
 	kill.$O\
@@ -71,6 +75,7 @@
 	opendir.$O\
 	pause.$O\
 	pipe.$O\
+	poll.$O\
 	profile.$O\
 	qlock.$O\
 	read.$O\
@@ -87,6 +92,7 @@
 	sleep.$O\
 	sqrt.$O\
 	stat.$O\
+	syslog.$O\
 	system.$O\
 	tcgetattr.$O\
 	time.$O\
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/poll.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/plan9/poll.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <poll.h>
+
+int
+poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+	int n;
+	fd_set rfds, wfds, efds;
+	struct timeval w, *wp;
+	struct pollfd *p, *ep;
+
+	n = -1;
+	FD_ZERO(&rfds);
+	FD_ZERO(&wfds);
+	FD_ZERO(&efds);
+
+	ep = fds + nfds;
+	for(p = fds; p < ep; p++){
+		if(p->fd < 0)
+			continue;
+		if((p->events&(POLLIN|POLLPRI|POLLOUT)) == 0)
+			continue;
+		if(p->events&POLLIN)
+			FD_SET(p->fd, &rfds);
+		if(p->events&POLLOUT)
+			FD_SET(p->fd, &wfds);
+		if(p->events&(POLLPRI))
+			FD_SET(p->fd, &efds);
+		if(p->fd > n)
+			n = p->fd;
+	}
+	wp = NULL;
+	if(timeout >= 0){
+		w.tv_sec = timeout/1000;
+		w.tv_usec = (timeout%1000)*1000;
+		wp = &w;
+	}
+	n = select(n+1, &rfds, &wfds, &efds, wp);
+	if(n < 0)
+		return -1;
+
+	/* POLLHUP means the socket is no longer connected. (FIN) */
+	/* POLLERR means the socket got an asynchronous error. (RST) */
+
+	for(p = fds; p < ep; p++){
+		p->revents = 0;
+		if(FD_ISSET(p->fd, &rfds))
+			p->revents |= POLLIN;
+		if(FD_ISSET(p->fd, &wfds))
+			p->revents |= POLLOUT;
+		if(FD_ISSET(p->fd, &efds))
+			p->revents |= POLLPRI|POLLHUP;
+	}
+	return n;
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/read.c
--- a/sys/src/ape/lib/ap/plan9/read.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/plan9/read.c	Fri Feb 12 10:59:32 2021 -0700
@@ -1,4 +1,5 @@
 #include <errno.h>
+#include <inttypes.h>
 #include <unistd.h>
 #include <string.h>
 #include "lib.h"
@@ -7,7 +8,7 @@
 #include <stdio.h>
 
 ssize_t
-read(int d, void *buf, size_t nbytes)
+pread(int d, void *buf, size_t nbytes, off_t offset)
 {
 	int n, noblock, isbuf;
 	Fdinfo *f;
@@ -38,9 +39,15 @@
 		}
 		n = _readbuf(d, buf, nbytes, noblock);
 	}else{
-		n = _READ(d, buf, nbytes);
+		n = _PREAD(d, buf, nbytes, offset);
 		if(n < 0)
 			_syserrno();
 	}
 	return n;
 }
+
+ssize_t
+read(int d, void *buf, size_t nbytes)
+{
+	return pread(d, buf, nbytes, -1LL);
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/syslog.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/plan9/syslog.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <syslog.h>
+
+static struct {
+	const char *ident;
+	char hostname[128];
+	int option;
+	int facility;
+	int fd;
+	int consfd;
+} flags = {
+	.fd = -1,
+	.consfd = -1,
+};
+
+void
+openlog(const char *ident, int option, int facility)
+{
+	char buf[1024];
+	int fd;
+
+	closelog();
+	if(gethostname(flags.hostname, sizeof(flags.hostname)) < 0)
+		return;
+	if(ident){
+		snprintf(buf, sizeof(buf), "/sys/log/%s", ident);
+		fd = open(buf, O_WRONLY);
+		if(fd < 0)
+			return;
+		if(fcntl(fd, F_SETFD, FD_CLOEXEC) < 0){
+			close(fd);
+			return;
+		}
+		flags.fd = fd;
+	}
+	if(option&LOG_CONS){
+		fd = open("/dev/cons", O_WRONLY);
+		if(fd < 0){
+			closelog();
+			return;
+		}
+		if(fcntl(fd, F_SETFD, FD_CLOEXEC) < 0){
+			closelog();
+			return;
+		}
+		flags.consfd = fd;
+	}
+	flags.ident = ident;
+	flags.option = option;
+	flags.facility = facility;
+}
+
+void
+syslog(int priority, const char *format, ...)
+{
+	char buf[128], *s, *p;
+	time_t t;
+	int n;
+	va_list arg;
+
+	/* syslog => Mar 10 01:45:50 $hostname $prog[$pid]: $msg */
+	/* plan9  => $hostname Mar 10 01:45:50 $msg */
+
+	USED(priority);
+
+	/* TODO: lock */
+	t = time(NULL);
+	s = ctime(&t);
+	p = buf + snprintf(buf, sizeof(buf)-1, "%s ", flags.hostname);
+	strncpy(p, s+4, 15);
+	p += 15;
+	*p++ = ' ';
+	va_start(arg, format);
+	p += vsnprintf(p, buf+sizeof(buf)-p-1, format, arg);
+	va_end(arg);
+	*p++ = '\n';
+	n = p - buf;
+	if(flags.fd >= 0){
+		lseek(flags.fd, 0, 2);
+		write(flags.fd, buf, n);
+	}
+	if(flags.consfd >= 0)
+		write(flags.consfd, buf, n);
+}
+
+void
+closelog(void)
+{
+	flags.ident = NULL;
+	flags.hostname[0] = '\0';
+	flags.option = 0;
+	flags.facility = 0;
+	if(flags.fd >= 0)
+		close(flags.fd);
+	flags.fd = -1;
+	if(flags.consfd >= 0)
+		close(flags.consfd);
+	flags.consfd = -1;
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/plan9/write.c
--- a/sys/src/ape/lib/ap/plan9/write.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/plan9/write.c	Fri Feb 12 10:59:32 2021 -0700
@@ -1,10 +1,11 @@
 #include <errno.h>
+#include <inttypes.h>
 #include <unistd.h>
 #include "lib.h"
 #include "sys9.h"
 
 ssize_t
-write(int d, const void *buf, size_t nbytes)
+pwrite(int d, const void *buf, size_t nbytes, off_t offset)
 {
 	int n;
 
@@ -14,8 +15,14 @@
 	}
 	if(_fdinfo[d].oflags&O_APPEND)
 		_SEEK(d, 0, 2);
-	n = _WRITE(d, buf, nbytes);
+	n = _PWRITE(d, buf, nbytes, offset);
 	if(n < 0)
 		_syserrno();
 	return n;
 }
+
+ssize_t
+write(int d, const void *buf, size_t nbytes)
+{
+	return pwrite(d, buf, nbytes, -1LL);
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/posix/basename.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/posix/basename.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+#include <string.h>
+
+char *
+basename(char *path)
+{
+	int n;
+	char *p;
+
+	if(path == NULL || path[0] == '\0')
+		return ".";
+	n = strlen(path);
+	if(n == 1 && path[0] == '/' && path[1] == '\0')
+		return "/";
+	while(path[n-1] == '/')
+		path[--n] = '\0';
+	p = strrchr(path, '/');
+	if(p == NULL)
+		return path;
+	return p+1;
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/posix/dirname.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/posix/dirname.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+#include <string.h>
+
+char *
+dirname(char *path)
+{
+	int n;
+	char *p;
+
+	if(path == NULL || path[0] == '\0')
+		return ".";
+	n = strlen(path);
+	if(n == 1 && path[0] == '/' && path[1] == '\0')
+		return "/";
+	while(path[n-1] == '/')
+		path[--n] = '\0';
+	p = strrchr(path, '/');
+	if(p == NULL)
+		return ".";
+	while(*p == '/')
+		*p-- = '\0';
+	if(path[0] == '\0')
+		return "/";
+	return path;
+}
diff -r 02e3059af5bc sys/src/ape/lib/ap/posix/getpagesize.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/ap/posix/getpagesize.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,7 @@
+#include <unistd.h>
+
+int
+getpagesize(void)
+{
+	return sysconf(_SC_PAGESIZE);
+}
diff -r bfe93397b157 sys/src/ape/lib/ap/posix/mkfile
--- a/sys/src/ape/lib/ap/posix/mkfile	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/posix/mkfile	Fri Feb 12 10:59:32 2021 -0700
@@ -2,7 +2,10 @@
 <$APE/config
 LIB=/$objtype/lib/ape/libap.a
 OFILES=\
+	basename.$O\
+	dirname.$O\
 	getgrent.$O\
+	getpagesize.$O\
 	getpwent.$O\
 	locale.$O\
 	mkfifo.$O\
diff -r bfe93397b157 sys/src/ape/lib/ap/posix/sysconf.c
--- a/sys/src/ape/lib/ap/posix/sysconf.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/posix/sysconf.c	Fri Feb 12 10:59:32 2021 -0700
@@ -36,6 +36,8 @@
 		return _POSIX_VERSION;
 	case _SC_LOGIN_NAME_MAX:
 		return L_cuserid;
+	case _SC_PAGESIZE:
+		return 4096;
 	}
 	errno = EINVAL;
 	return -1;
diff -r bfe93397b157 sys/src/ape/lib/ap/stdio/_IO_putc.c
--- a/sys/src/ape/lib/ap/stdio/_IO_putc.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/stdio/_IO_putc.c	Fri Feb 12 10:59:32 2021 -0700
@@ -51,8 +51,13 @@
 				f->bufl+=BUFSIZ;
 				f->rp=t+f->bufl;
 			}else{
-				f->state=ERR;
-				return EOF;
+				/*
+				 * [v]snprintf should return number of characters
+				 * which would have written if enough space had enough available.
+				 * however sprintf is not.
+				 */
+				f->state=WR;
+				return c&0xff;
 			}
 		}
 		*f->wp++=c;
diff -r bfe93397b157 sys/src/ape/lib/ap/stdio/sclose.c
--- a/sys/src/ape/lib/ap/stdio/sclose.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/stdio/sclose.c	Fri Feb 12 10:59:32 2021 -0700
@@ -29,6 +29,8 @@
 					goto Error;
 				f->buf=t;
 				f->wp=t+f->bufl;
+			} else if(f->buf==NULL){
+				return NULL;
 			} else {
 				if(f->wp > f->buf)
 					*(f->wp-1) = '\0';
diff -r bfe93397b157 sys/src/ape/lib/ap/stdio/strerror.c
--- a/sys/src/ape/lib/ap/stdio/strerror.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/stdio/strerror.c	Fri Feb 12 10:59:32 2021 -0700
@@ -77,7 +77,17 @@
 
 	/* These added in 1003.1b-1993 */
 	"Operation canceled",
-	"Operation in progress"
+	"Operation in progress",
+
+	/* from research unix */
+	"Text file is busy",			/* ETXTBSY */
+
+	/* Added in more recent 1003.x versions */
+	"Operation already in progress",	/* EALREADY */
+	"Connection reset by peer",		/* ECONNRESET */
+
+	"Value too large for defined data type", /* EOVERFLOW */
+	"Too many symbolic links encountered",	/* ELOOP */
 };
 #define	_IO_nerr	(sizeof sys_errlist/sizeof sys_errlist[0])
 int sys_nerr = _IO_nerr;
diff -r bfe93397b157 sys/src/ape/lib/ap/stdio/vfprintf.c
--- a/sys/src/ape/lib/ap/stdio/vfprintf.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/ap/stdio/vfprintf.c	Fri Feb 12 10:59:32 2021 -0700
@@ -215,7 +215,7 @@
 		}
 		return -1;
 	}
-	return nprint;
+	return ferror(f) ? -1 : nprint;
 }
 
 static int
diff -r bfe93397b157 sys/src/ape/lib/bsd/arc4random.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/bsd/arc4random.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,30 @@
+#include <u.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <libsec.h>
+
+void
+arc4random_buf(void *buf, size_t nbytes)
+{
+	genrandom(buf, nbytes);
+}
+
+unsigned int
+arc4random(void)
+{
+	uint v;
+
+	arc4random_buf(&v, sizeof v);
+	return v;
+}
+
+int
+getentropy(void *buf, size_t len)
+{
+	if (len > 256) {
+		errno = EIO;
+		return -1;
+	}
+	genrandom(buf, len);
+	return 0;
+}
diff -r 8b4cfdf43705 sys/src/ape/lib/bsd/gethostname.c
--- a/sys/src/ape/lib/bsd/gethostname.c	Tue Feb 16 22:04:50 2021 +0100
+++ b/sys/src/ape/lib/bsd/gethostname.c	Tue Feb 16 21:43:40 2021 -0700
@@ -6,7 +6,7 @@
 #include <string.h>
 
 int
-gethostname(char *name, int namelen)
+gethostname(char *name, size_t namelen)
 {
 	int n, fd;
 	char buf[128];
diff -r bfe93397b157 sys/src/ape/lib/bsd/getprogname.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/bsd/getprogname.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,7 @@
+#include <lib9.h>
+
+const char *
+getprogname(void)
+{
+	return argv0;
+}
diff -r bfe93397b157 sys/src/ape/lib/bsd/mkfile
--- a/sys/src/ape/lib/bsd/mkfile	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/bsd/mkfile	Fri Feb 12 10:59:32 2021 -0700
@@ -4,6 +4,7 @@
 LIB=/$objtype/lib/ape/libbsd.a
 OFILES=\
 	accept.$O\
+	arc4random.$O\
 	bcopy.$O\
 	bind.$O\
 	connect.$O\
@@ -19,6 +20,7 @@
 	getopt.$O\
 	getpeername.$O\
 	getprotobyname.$O\
+	getprogname.$O\
 	getservbyaddr.$O\
 	getservbyname.$O\
 	getsockname.$O\
@@ -41,6 +43,7 @@
 	send.$O\
 	sendto.$O\
 	setlinebuf.$O\
+	setprogname.$O\
 	shutdown.$O\
 	_sock_ingetaddr.$O\
 	_sock_ipattr.$O\
diff -r bfe93397b157 sys/src/ape/lib/bsd/setprogname.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/ape/lib/bsd/setprogname.c	Fri Feb 12 10:59:32 2021 -0700
@@ -0,0 +1,7 @@
+#include <lib9.h>
+
+void
+setprogname(const char *progname)
+{
+	argv0 = (char *)progname;
+}
diff -r bfe93397b157 sys/src/ape/lib/bsd/socket.c
--- a/sys/src/ape/lib/bsd/socket.c	Wed Sep 16 20:45:49 2020 +0000
+++ b/sys/src/ape/lib/bsd/socket.c	Fri Feb 12 10:59:32 2021 -0700
@@ -180,9 +180,23 @@
 /*
  * probably should do better than this
  */
-int getsockopt(int, int, int, void *, int *)
+int getsockopt(int fd, int level, int opt, void *v, int *len)
 {
-	return -1;
+	// should we check what fd is socket?
+	USED(fd, len);
+
+	if(level != SOL_SOCKET){
+		errno = ENOPROTOOPT;
+		return -1;
+	}
+	switch(opt){
+	case SO_ERROR:
+		*(int *)v = 0;
+		return 0;
+	default:
+		errno = EINVAL;
+		return -1;
+	}
 }
 
 int setsockopt(int, int, int, void *, int)
diff -r 3540943c10e8 sys/src/cmd/python/pyconfig.h
--- a/sys/src/cmd/python/pyconfig.h	Thu Feb 18 15:13:25 2021 +0100
+++ b/sys/src/cmd/python/pyconfig.h	Thu Feb 18 15:23:05 2021 -0700
@@ -46,7 +46,7 @@
 
 #define SIGWINCH 21	/* for curses */
 
-#define S_ISSOCK S_ISFIFO /* for hg, see /sys/include/ape/sys/stat.h */
+/* #define S_ISSOCK S_ISFIFO for hg, see /sys/include/ape/sys/stat.h */
 
 /* Define if --enable-ipv6 is specified */
 #define ENABLE_IPV6 1

  parent reply	other threads:[~2021-02-26 19:47 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-22  2:48 [9front] " bsdsm
2021-02-22  4:14 ` ori
2021-02-22  5:20   ` Jens Staal
2021-02-25  2:15 ` ori
2021-02-25  2:21   ` ori
2021-02-25 16:37     ` Aaron
2021-02-25 18:06       ` ori
2021-02-26 10:28         ` cinap_lenrek
2021-02-26 15:38           ` Lucas Francesco
2021-02-26 19:23 ` bsdsm [this message]
2021-03-01  3:41   ` [9front] " ori
2021-03-15  3:20   ` ori
2021-03-15  3:36   ` ori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5591aeb1a24fac8a3e472085c5be336c.squirrel@mx.sdf.org \
    --to=bsdsm@sdf.org \
    --cc=9front@9front.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).