From: ori@eigenstate.org
To: 9front@9front.org
Subject: Re: [9front] Re: [Patch] APE changes (2019 Lufia patches)
Date: Sun, 14 Mar 2021 20:20:51 -0700 [thread overview]
Message-ID: <19EFFC9D45177C6E847378A6F4111EAC@eigenstate.org> (raw)
In-Reply-To: <5591aeb1a24fac8a3e472085c5be336c.squirrel@mx.sdf.org>
Quoth bsdsm@sdf.org:
>
> 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.
Alright, finally started looking over the pthreads patch,
since it's the most interesting.
>
> 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>
We need to be careful here -- this litters the namespace,
in a way that it strictly shouldn't. the types that get
dragged in should, in theory, get prefixed by an '_' or
'__' to prevent namespace clashes.
> +
> +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,
This is an odd limit. As far as I can tell, this is entirely
due to the privates array -- if we move the array contents
into the pthread itself, we can remove the limit.
> +
> + 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
Typo: NORMAL. We should also use an enum here,
and
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
> +#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
To get the namespacing, we should get rid of the _LOCK_EXTENSION
define from pthread.; instead, we should do something like:
typedef struct _Rendez _Rendez;
#ifdef _LOCK_EXTENSION
typedef _Rendez Rendez;
#endif
> @@ -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
Dead code should be deleted.
> +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))
> +{
I think we need a lock to protect these handlers.
> + 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);
Need to be careful -- are there any other places that can fork?
system()?
> 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];
I think that 'privileges' is a misunderstanding of the
'priv' abbreviation -- I think we want 'privates' here.
I also don't think this should be a global array, but
something that we put into the pthread_t itself.
typedef Thread* pthread_t;
We can even use privalloc() here, but I don't think
we need to.
I think this is an invasive enough change that I can
do another round after it gets done.
> +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;
> + }
This loop is wrong -- if the threads exit out of
order, then we lose the wait messages and never
join. We'll probably need to set up some sort of
wait notification dance -- possibly an exit cond
var for non-detached threads.
> + 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/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){
Abort if it's less than zero -- let's not paper over
programmer issues.
> + 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/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();
Obviously, this would need to change to use
privalloc() or similar once we get rid of the
priv array.
next prev parent reply other threads:[~2021-03-15 3:25 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 ` [9front] " bsdsm
2021-03-01 3:41 ` ori
2021-03-15 3:20 ` ori [this message]
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=19EFFC9D45177C6E847378A6F4111EAC@eigenstate.org \
--to=ori@eigenstate.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).