summaryrefslogtreecommitdiff
path: root/thread.h
blob: 79064e494e6648992fcfe339a7726698e5b20f75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
#ifdef USE_THREADS

#ifdef WIN32
#  include "win32/win32thread.h"
#endif

/* POSIXish threads */
typedef pthread_t perl_thread;
#ifdef OLD_PTHREADS_API
#  define pthread_mutexattr_init(a) pthread_mutexattr_create(a)
#  define pthread_mutexattr_settype(a,t) pthread_mutexattr_setkind_np(a,t)
#  define pthread_key_create(k,d) pthread_keycreate(k,(pthread_destructor_t)(d))
#  define YIELD pthread_yield()
#  define DETACH(t)				\
    STMT_START {				\
	if (pthread_detach(&(t)->self)) {	\
	    MUTEX_UNLOCK(&(t)->mutex);		\
	    croak("panic: DETACH");		\
	}					\
    } STMT_END
#else
#  define pthread_mutexattr_default NULL
#  define pthread_condattr_default NULL
#  define pthread_attr_default NULL
#endif /* OLD_PTHREADS_API */

#ifndef YIELD
#  define YIELD sched_yield()
#endif

#ifndef MUTEX_INIT
#define MUTEX_INIT(m)						\
    STMT_START {						\
	if (pthread_mutex_init((m), pthread_mutexattr_default))	\
	    croak("panic: MUTEX_INIT");				\
    } STMT_END
#define MUTEX_LOCK(m)				\
    STMT_START {				\
	if (pthread_mutex_lock((m)))		\
	    croak("panic: MUTEX_LOCK");		\
    } STMT_END
#define MUTEX_UNLOCK(m)				\
    STMT_START {				\
	if (pthread_mutex_unlock((m)))		\
	    croak("panic: MUTEX_UNLOCK");	\
    } STMT_END
#define MUTEX_DESTROY(m)			\
    STMT_START {				\
	if (pthread_mutex_destroy((m)))		\
	    croak("panic: MUTEX_DESTROY");	\
    } STMT_END
#endif /* MUTEX_INIT */

#ifndef COND_INIT
#define COND_INIT(c)						\
    STMT_START {						\
	if (pthread_cond_init((c), pthread_condattr_default))	\
	    croak("panic: COND_INIT");				\
    } STMT_END
#define COND_SIGNAL(c)				\
    STMT_START {				\
	if (pthread_cond_signal((c)))		\
	    croak("panic: COND_SIGNAL");	\
    } STMT_END
#define COND_BROADCAST(c)			\
    STMT_START {				\
	if (pthread_cond_broadcast((c)))	\
	    croak("panic: COND_BROADCAST");	\
    } STMT_END
#define COND_WAIT(c, m)				\
    STMT_START {				\
	if (pthread_cond_wait((c), (m)))	\
	    croak("panic: COND_WAIT");		\
    } STMT_END
#define COND_DESTROY(c)				\
    STMT_START {				\
	if (pthread_cond_destroy((c)))		\
	    croak("panic: COND_DESTROY");	\
    } STMT_END
#endif /* COND_INIT */

/* DETACH(t) must only be called while holding t->mutex */
#ifndef DETACH
#define DETACH(t)				\
    STMT_START {				\
	if (pthread_detach((t)->self)) {	\
	    MUTEX_UNLOCK(&(t)->mutex);		\
	    croak("panic: DETACH");		\
	}					\
    } STMT_END
#endif /* DETACH */

#ifndef JOIN
#define JOIN(t, avp) 					\
    STMT_START {					\
	if (pthread_join((t)->self, (void**)(avp)))	\
	    croak("panic: pthread_join");		\
    } STMT_END
#endif /* JOIN */

#ifndef SET_THR
#define SET_THR(t)					\
    STMT_START {					\
	if (pthread_setspecific(thr_key, (void *) (t)))	\
	    croak("panic: pthread_setspecific");	\
    } STMT_END
#endif /* SET_THR */

#ifndef THR
#  ifdef OLD_PTHREADS_API
struct thread *getTHR _((void));
#    define THR getTHR()
#  else
#    define THR ((struct thread *) pthread_getspecific(thr_key))
#  endif /* OLD_PTHREADS_API */
#endif /* THR */

#ifndef dTHR
#  define dTHR struct thread *thr = THR
#endif /* dTHR */

#ifndef INIT_THREADS
#  ifdef NEED_PTHREAD_INIT
#    define INIT_THREADS pthread_init()
#  else
#    define INIT_THREADS NOOP
#  endif
#endif

#ifndef THREAD_RET_TYPE
#  define THREAD_RET_TYPE	void *
#  define THREAD_RET_CAST(p)	((void *)(p))
#endif /* THREAD_RET */

struct thread {
    /* The fields that used to be global */
    /* Important ones in the first cache line (if alignment is done right) */
    SV **	Tstack_sp;
#ifdef OP_IN_REGISTER
    OP *	Topsave;
#else
    OP *	Top;
#endif
    SV **	Tcurpad;
    SV **	Tstack_base;

    SV **	Tstack_max;

    I32 *	Tscopestack;
    I32		Tscopestack_ix;
    I32		Tscopestack_max;

    ANY *	Tsavestack;
    I32		Tsavestack_ix;
    I32		Tsavestack_max;

    OP **	Tretstack;
    I32		Tretstack_ix;
    I32		Tretstack_max;

    I32 *	Tmarkstack;
    I32 *	Tmarkstack_ptr;
    I32 *	Tmarkstack_max;

    SV *	TSv;
    XPV *	TXpv;
    struct stat	Tstatbuf;
    struct tms	Ttimesbuf;
    
    /* XXX What about regexp stuff? */

    /* Now the fields that used to be "per interpreter" (even when global) */

    /* Fields used by magic variables such as $@, $/ and so on */
    bool	Ttainted;
    PMOP *	Tcurpm;
    SV *	Tnrs;
    SV *	Trs;
    GV *	Tlast_in_gv;
    char *	Tofs;
    STRLEN	Tofslen;
    GV *	Tdefoutgv;
    char *	Tchopset;
    SV *	Tformtarget;
    SV *	Tbodytarget;
    SV *	Ttoptarget;

    /* Stashes */
    HV *	Tdefstash;
    HV *	Tcurstash;

    /* Stacks */
    SV **	Ttmps_stack;
    I32		Ttmps_ix;
    I32		Ttmps_floor;
    I32		Ttmps_max;

    int		Tin_eval;
    OP *	Trestartop;
    int		Tdelaymagic;
    bool	Tdirty;
    U8		Tlocalizing;
    COP *	Tcurcop;

    CONTEXT *	Tcxstack;
    I32		Tcxstack_ix;
    I32		Tcxstack_max;

    AV *	Tcurstack;
    AV *	Tmainstack;
    JMPENV *	Ttop_env;
    I32		Trunlevel;

    /* XXX Sort stuff, firstgv, secongv and so on? */

    SV *	oursv;
    HV *	cvcache;
    perl_thread	self;			/* Underlying thread object */
    U32		flags;
    AV *	magicals;		/* Per-thread magicals */
    AV *	specific;		/* Thread-specific user data */
    SV *	errsv;			/* Backing SV for $@ */
    HV *	errhv;			/* HV for what was %@ in pp_ctl.c */
    perl_mutex	mutex;			/* For the fields others can change */
    U32		tid;
    struct thread *next, *prev;		/* Circular linked list of threads */

#ifdef ADD_THREAD_INTERN
    struct thread_intern i;		/* Platform-dependent internals */
#endif
    char	trailing_nul;		/* For the sake of thrsv and oursv */
};

typedef struct thread *Thread;

/* Values and macros for thr->flags */
#define THRf_STATE_MASK	7
#define THRf_R_JOINABLE	0
#define THRf_R_JOINED	1
#define THRf_R_DETACHED	2
#define THRf_ZOMBIE	3
#define THRf_DEAD	4

#define THRf_DIE_FATAL	8

/* ThrSTATE(t) and ThrSETSTATE(t) must only be called while holding t->mutex */
#define ThrSTATE(t) ((t)->flags)
#define ThrSETSTATE(t, s) STMT_START {		\
	(t)->flags &= ~THRf_STATE_MASK;		\
	(t)->flags |= (s);			\
	DEBUG_L(PerlIO_printf(PerlIO_stderr(),	\
			      "thread %p set to state %d\n", (t), (s))); \
    } STMT_END

typedef struct condpair {
    perl_mutex	mutex;		/* Protects all other fields */
    perl_cond	owner_cond;	/* For when owner changes at all */
    perl_cond	cond;		/* For cond_signal and cond_broadcast */
    Thread	owner;		/* Currently owning thread */
} condpair_t;

#define MgMUTEXP(mg) (&((condpair_t *)(mg->mg_ptr))->mutex)
#define MgOWNERCONDP(mg) (&((condpair_t *)(mg->mg_ptr))->owner_cond)
#define MgCONDP(mg) (&((condpair_t *)(mg->mg_ptr))->cond)
#define MgOWNER(mg) ((condpair_t *)(mg->mg_ptr))->owner

#undef	stack_base
#undef	stack_sp
#undef	stack_max
#undef	curstack
#undef	mainstack
#undef	markstack
#undef	markstack_ptr
#undef	markstack_max
#undef	scopestack
#undef	scopestack_ix
#undef	scopestack_max
#undef	savestack
#undef	savestack_ix
#undef	savestack_max
#undef	retstack
#undef	retstack_ix
#undef	retstack_max
#undef	curcop
#undef	cxstack
#undef	cxstack_ix
#undef	cxstack_max
#undef	defstash
#undef	curstash
#undef	tmps_stack
#undef	tmps_floor
#undef	tmps_ix
#undef	tmps_max
#undef	curpad
#undef	Sv
#undef	Xpv
#undef	statbuf
#undef	timesbuf
#undef	tainted
#undef	curpm
#undef	nrs
#undef	rs
#undef	last_in_gv
#undef	ofs
#undef	ofslen
#undef	defoutgv
#undef	chopset
#undef	formtarget
#undef	bodytarget
#undef	toptarget
#undef	top_env
#undef	runlevel
#undef	in_eval
#undef	restartop
#undef	delaymagic
#undef	dirty
#undef	localizing

#define stack_base	(thr->Tstack_base)
#define stack_sp	(thr->Tstack_sp)
#define stack_max	(thr->Tstack_max)
#ifdef OP_IN_REGISTER
#define opsave		(thr->Topsave)
#else
#undef	op
#define op		(thr->Top)
#endif
#define	curcop		(thr->Tcurcop)
#define	stack		(thr->Tstack)
#define curstack	(thr->Tcurstack)
#define	mainstack	(thr->Tmainstack)
#define	markstack	(thr->Tmarkstack)
#define	markstack_ptr	(thr->Tmarkstack_ptr)
#define	markstack_max	(thr->Tmarkstack_max)
#define	scopestack	(thr->Tscopestack)
#define	scopestack_ix	(thr->Tscopestack_ix)
#define	scopestack_max	(thr->Tscopestack_max)

#define	savestack	(thr->Tsavestack)
#define	savestack_ix	(thr->Tsavestack_ix)
#define	savestack_max	(thr->Tsavestack_max)

#define	retstack	(thr->Tretstack)
#define	retstack_ix	(thr->Tretstack_ix)
#define	retstack_max	(thr->Tretstack_max)

#define	cxstack		(thr->Tcxstack)
#define	cxstack_ix	(thr->Tcxstack_ix)
#define	cxstack_max	(thr->Tcxstack_max)

#define curpad		(thr->Tcurpad)
#define Sv		(thr->TSv)
#define Xpv		(thr->TXpv)
#define statbuf		(thr->Tstatbuf)
#define timesbuf	(thr->Ttimesbuf)
#define	tainted		(thr->Ttainted)
#define	tainted		(thr->Ttainted)
#define	curpm		(thr->Tcurpm)
#define	nrs		(thr->Tnrs)
#define	rs		(thr->Trs)
#define	last_in_gv	(thr->Tlast_in_gv)
#define	ofs		(thr->Tofs)
#define	ofslen		(thr->Tofslen)
#define	defoutgv	(thr->Tdefoutgv)
#define	chopset		(thr->Tchopset)
#define	formtarget	(thr->Tformtarget)
#define	bodytarget	(thr->Tbodytarget)
#define	toptarget	(thr->Ttoptarget)
#define defstash	(thr->Tdefstash)
#define curstash	(thr->Tcurstash)

#define tmps_stack	(thr->Ttmps_stack)
#define tmps_ix		(thr->Ttmps_ix)
#define tmps_floor	(thr->Ttmps_floor)
#define tmps_max	(thr->Ttmps_max)

#define in_eval		(thr->Tin_eval)
#define restartop	(thr->Trestartop)
#define delaymagic	(thr->Tdelaymagic)
#define dirty		(thr->Tdirty)
#define localizing	(thr->Tlocalizing)

#define	top_env		(thr->Ttop_env)
#define	runlevel	(thr->Trunlevel)

#else
/* USE_THREADS is not defined */
#define MUTEX_LOCK(m)
#define MUTEX_UNLOCK(m)
#define MUTEX_INIT(m)
#define MUTEX_DESTROY(m)
#define COND_INIT(c)
#define COND_SIGNAL(c)
#define COND_BROADCAST(c)
#define COND_WAIT(c, m)
#define COND_DESTROY(c)

#define THR
/* Rats: if dTHR is just blank then the subsequent ";" throws an error */
#define dTHR extern int errno
#endif /* USE_THREADS */