tpthread.c - plan9port - [fork] Plan 9 from user space
HTML git clone git://src.adamsgaard.dk/plan9port
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
tpthread.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 }