plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

pthread.c (3323B)


      1 #include "threadimpl.h"
      2 
      3 #undef exits
      4 #undef _exits
      5 
      6 static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
      7 
      8 static void
      9 lockinit(Lock *lk)
     10 {
     11 	pthread_mutexattr_t attr;
     12 
     13 	pthread_mutex_lock(&initmutex);
     14 	if(lk->init == 0){
     15 		pthread_mutexattr_init(&attr);
     16 		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
     17 		pthread_mutex_init(&lk->mutex, &attr);
     18 		pthread_mutexattr_destroy(&attr);
     19 		lk->init = 1;
     20 	}
     21 	pthread_mutex_unlock(&initmutex);
     22 }
     23 
     24 int
     25 _threadlock(Lock *lk, int block, ulong pc)
     26 {
     27 	int r;
     28 
     29 	if(!lk->init)
     30 		lockinit(lk);
     31 	if(block){
     32 		if(pthread_mutex_lock(&lk->mutex) != 0)
     33 			abort();
     34 		return 1;
     35 	}else{
     36 		r = pthread_mutex_trylock(&lk->mutex);
     37 		if(r == 0)
     38 			return 1;
     39 		if(r == EBUSY)
     40 			return 0;
     41 		abort();
     42 		return 0;
     43 	}
     44 }
     45 
     46 void
     47 _threadunlock(Lock *lk, ulong pc)
     48 {
     49 	if(pthread_mutex_unlock(&lk->mutex) != 0)
     50 		abort();
     51 }
     52 
     53 /* note: _procsleep can have spurious wakeups, like pthread_cond_wait */
     54 void
     55 _procsleep(_Procrendez *r)
     56 {
     57 	/* r is protected by r->l, which we hold */
     58 	pthread_cond_init(&r->cond, 0);
     59 	r->asleep = 1;
     60 	if(pthread_cond_wait(&r->cond, &r->l->mutex) != 0)
     61 		sysfatal("pthread_cond_wait: %r");
     62 	pthread_cond_destroy(&r->cond);
     63 	r->asleep = 0;
     64 }
     65 
     66 void
     67 _procwakeup(_Procrendez *r)
     68 {
     69 	if(r->asleep){
     70 		r->asleep = 0;
     71 		pthread_cond_signal(&r->cond);
     72 	}
     73 }
     74 
     75 void
     76 _procwakeupandunlock(_Procrendez *r)
     77 {
     78 	if(r->asleep){
     79 		r->asleep = 0;
     80 		pthread_cond_signal(&r->cond);
     81 	}
     82 	unlock(r->l);
     83 }
     84 
     85 static void
     86 startprocfn(void *v)
     87 {
     88 	void **a;
     89 	void (*fn)(void*);
     90 	Proc *p;
     91 
     92 	a = (void**)v;
     93 	fn = (void(*)(void*))a[0];
     94 	p = a[1];
     95 	free(a);
     96 	p->osprocid = pthread_self();
     97 	pthread_detach(p->osprocid);
     98 
     99 	(*fn)(p);
    100 
    101 	pthread_exit(0);
    102 }
    103 
    104 static void
    105 startpthreadfn(void *v)
    106 {
    107 	void **a;
    108 	Proc *p;
    109 	_Thread *t;
    110 
    111 	a = (void**)v;
    112 	p = a[0];
    113 	t = a[1];
    114 	free(a);
    115 	t->osprocid = pthread_self();
    116 	pthread_detach(t->osprocid);
    117 	_threadpthreadmain(p, t);
    118 	pthread_exit(0);
    119 }
    120 
    121 void
    122 _procstart(Proc *p, void (*fn)(Proc*))
    123 {
    124 	void **a;
    125 
    126 	a = malloc(2*sizeof a[0]);
    127 	if(a == nil)
    128 		sysfatal("_procstart malloc: %r");
    129 	a[0] = (void*)fn;
    130 	a[1] = p;
    131 
    132 	if(pthread_create(&p->osprocid, nil, (void*(*)(void*))startprocfn, (void*)a) < 0){
    133 		fprint(2, "pthread_create: %r\n");
    134 		abort();
    135 	}
    136 }
    137 
    138 void
    139 _threadpthreadstart(Proc *p, _Thread *t)
    140 {
    141 	void **a;
    142 
    143 	a = malloc(3*sizeof a[0]);
    144 	if(a == nil)
    145 		sysfatal("_pthreadstart malloc: %r");
    146 	a[0] = p;
    147 	a[1] = t;
    148 	if(pthread_create(&t->osprocid, nil, (void*(*)(void*))startpthreadfn, (void*)a) < 0){
    149 		fprint(2, "pthread_create: %r\n");
    150 		abort();
    151 	}
    152 }
    153 
    154 static pthread_key_t prockey;
    155 
    156 Proc*
    157 _threadproc(void)
    158 {
    159 	Proc *p;
    160 
    161 	p = pthread_getspecific(prockey);
    162 	return p;
    163 }
    164 
    165 void
    166 _threadsetproc(Proc *p)
    167 {
    168 	pthread_setspecific(prockey, p);
    169 }
    170 
    171 void
    172 _pthreadinit(void)
    173 {
    174 	static struct utsname un;
    175 	pthread_t id;
    176 
    177 	if(uname(&un) < 0)
    178 		fprint(2, "warning: uname failed: %r\n");
    179 	if(strcmp(un.sysname, "Linux") == 0){
    180 		/*
    181 		 * Want to distinguish between the old LinuxThreads pthreads
    182 		 * and the new NPTL implementation.  NPTL uses much bigger
    183 		 * thread IDs.
    184 		 */
    185 		id = pthread_self();
    186 		if(*(ulong*)(void*)&id < 1024*1024)
    187 			sysfatal("cannot use LinuxThreads as pthread library; see %s/src/libthread/README.Linux", get9root());
    188 	}
    189 	pthread_key_create(&prockey, 0);
    190 }
    191 
    192 void
    193 threadexitsall(char *msg)
    194 {
    195 	exits(msg);
    196 }
    197 
    198 void
    199 _threadpexit(void)
    200 {
    201 	pthread_exit(0);
    202 }