[t][TT #763] Fix is_deeply() on hashes with undefs and add tests
[parrot.git] / include / parrot / thread.h
blob200220a6fe28de8635890408d164d472590db661
1 /* thread.h
2 * Copyright (C) 2001-2007, Parrot Foundation.
3 * SVN Info
4 * $Id$
5 * Overview:
6 * This is the api header for the thread primitives
7 * Data Structure and Algorithms:
8 * History:
9 * Notes:
10 * References:
13 #ifndef PARROT_THREAD_H_GUARD
14 #define PARROT_THREAD_H_GUARD
16 # include "parrot/parrot.h"
17 # include "parrot/atomic.h"
19 #ifndef PARROT_HAS_THREADS
21 # define LOCK(m)
22 # define UNLOCK(m)
23 # define COND_WAIT(c, m)
24 # define COND_TIMED_WAIT(c, m, t)
25 # define COND_SIGNAL(c)
26 # define COND_BROADCAST(c)
28 # define MUTEX_INIT(m)
29 # define MUTEX_DESTROY(m)
31 # define COND_INIT(c)
32 # define COND_DESTROY(c)
34 # define THREAD_CREATE_DETACHED(t, func, arg)
35 # define THREAD_CREATE_JOINABLE(t, func, arg)
37 # define JOIN(t, ret)
38 # define DETACH(t)
40 # define CLEANUP_PUSH(f, a)
41 # define CLEANUP_POP(a)
43 # define Parrot_mutex int
44 # define Parrot_cond int
45 # define Parrot_thread int
47 typedef void (*Cleanup_Handler)(void *);
49 # ifndef __timespec_defined
50 # define __timespec_defined
51 struct timespec {
52 time_t tv_sec;
53 long tv_nsec;
55 # endif /* __timespec_defined */
57 #endif /* PARROT_HAS_THREADS */
59 #ifndef YIELD
60 # define YIELD
61 #endif /* YIELD */
63 typedef enum {
64 THREAD_STATE_JOINABLE, /* default */
65 THREAD_STATE_DETACHED = 0x01, /* i.e. non-joinable */
66 THREAD_STATE_JOINED = 0x02, /* JOIN was issued */
67 THREAD_STATE_FINISHED = 0x04, /* the thread function has ended */
68 THREAD_STATE_NOT_STARTED = 0x08, /* the thread wasn't started */
69 THREAD_STATE_SUSPENDED_GC = 0x10, /* suspended for GC on request */
70 THREAD_STATE_GC_WAKEUP = 0x20, /* the thread is waiting on its condition
71 variable, and will do a GC run if
72 it is woken up and marked as suspended
73 for GC */
74 THREAD_STATE_SUSPEND_GC_REQUESTED = 0x40 /* the thread's event queue
75 contains a suspend-for-GC event */
76 } thread_state_enum;
80 * per interpreter thread data structure
82 typedef struct _Thread_data {
83 Parrot_thread thread; /* pthread_t or such */
84 INTVAL state;
85 int wants_shared_gc; /* therad is trying to
86 do a shared GC run */
87 UINTVAL tid; /* 0.. n-1 idx in interp array */
89 Parrot_Interp joiner; /* thread that is trying to join this */
91 /* for wr access to interpreter e.g. for GC
92 * if only used for GC the lock could be in the arena
93 * instead here, or in the interpreter, with negative size impact
94 * for the non-threaded case
96 Parrot_mutex interp_lock;
98 /* for waking up the interpreter from various sorts
99 * of sleeping
101 Parrot_cond interp_cond;
103 /* COW'd constant tables */
104 Hash *const_tables;
105 } Thread_data;
107 # define LOCK_INTERPRETER(interp) \
108 if ((interp)->thread_data) \
109 LOCK((interp)->thread_data->interp_lock)
110 # define UNLOCK_INTERPRETER(interp) \
111 if ((interp)->thread_data) \
112 UNLOCK((interp)->thread_data->interp_lock)
114 # define INTERPRETER_LOCK_INIT(interp) \
115 do { \
116 MUTEX_INIT((interp)->thread_data->interp_lock); \
117 COND_INIT((interp)->thread_data->interp_cond); \
118 } while (0)
119 # define INTERPRETER_LOCK_DESTROY(interp) \
120 do { \
121 MUTEX_DESTROY((interp)->thread_data->interp_lock); \
122 COND_DESTROY((interp)->thread_data->interp_cond); \
123 } while (0)
127 * this global mutex protects the list of interpreters
129 VAR_SCOPE Parrot_mutex interpreter_array_mutex;
130 VAR_SCOPE Interp ** interpreter_array;
131 VAR_SCOPE size_t n_interpreters;
133 typedef enum {
134 THREAD_GC_STAGE_NONE,
135 THREAD_GC_STAGE_MARK,
136 THREAD_GC_STAGE_SWEEP = THREAD_GC_STAGE_NONE
137 } thread_gc_stage_enum;
139 typedef struct _Shared_gc_info {
140 thread_gc_stage_enum gc_stage;
141 Parrot_cond gc_cond;
142 int num_reached;
144 Parrot_atomic_integer gc_block_level;
145 } Shared_gc_info;
147 /* TODO use thread pools instead */
148 VAR_SCOPE Shared_gc_info *shared_gc_info;
150 typedef struct _Sync {
151 Parrot_Interp owner; /* that interpreter, that owns
152 the arena, where the PMC is in */
153 Parrot_mutex pmc_lock; /* for wr access to PMCs content */
154 } Sync;
156 /* HEADERIZER BEGIN: src/thread.c */
157 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
159 PARROT_EXPORT
160 void Parrot_shared_gc_block(PARROT_INTERP)
161 __attribute__nonnull__(1);
163 PARROT_EXPORT
164 void Parrot_shared_gc_unblock(PARROT_INTERP)
165 __attribute__nonnull__(1);
167 void pt_add_to_interpreters(PARROT_INTERP,
168 ARGIN_NULLOK(Parrot_Interp new_interp))
169 __attribute__nonnull__(1);
171 void pt_clone_code(Parrot_Interp d, Parrot_Interp s);
172 void pt_clone_globals(Parrot_Interp d, Parrot_Interp s);
173 void pt_free_pool(PARROT_INTERP)
174 __attribute__nonnull__(1);
176 void pt_gc_mark_root_finished(PARROT_INTERP)
177 __attribute__nonnull__(1);
179 void pt_gc_start_mark(PARROT_INTERP)
180 __attribute__nonnull__(1);
182 void pt_gc_stop_mark(PARROT_INTERP)
183 __attribute__nonnull__(1);
185 void pt_join_threads(PARROT_INTERP)
186 __attribute__nonnull__(1);
188 PARROT_CAN_RETURN_NULL
189 PMC * pt_shared_fixup(PARROT_INTERP, ARGMOD(PMC *pmc))
190 __attribute__nonnull__(1)
191 __attribute__nonnull__(2)
192 FUNC_MODIFIES(*pmc);
194 void pt_suspend_self_for_gc(PARROT_INTERP)
195 __attribute__nonnull__(1);
197 void pt_thread_detach(UINTVAL tid);
198 PARROT_CAN_RETURN_NULL
199 PMC* pt_thread_join(NOTNULL(Parrot_Interp parent), UINTVAL tid)
200 __attribute__nonnull__(1);
202 void pt_thread_kill(UINTVAL tid);
203 void pt_thread_prepare_for_run(Parrot_Interp d, NULLOK(Parrot_Interp s));
204 int pt_thread_run(PARROT_INTERP,
205 ARGOUT(PMC *dest_interp),
206 ARGIN(PMC *sub),
207 ARGIN_NULLOK(PMC *arg))
208 __attribute__nonnull__(1)
209 __attribute__nonnull__(2)
210 __attribute__nonnull__(3)
211 FUNC_MODIFIES(*dest_interp);
213 int pt_thread_run_1(PARROT_INTERP,
214 ARGOUT(PMC* dest_interp),
215 ARGIN(PMC* sub),
216 ARGIN(PMC *arg))
217 __attribute__nonnull__(1)
218 __attribute__nonnull__(2)
219 __attribute__nonnull__(3)
220 __attribute__nonnull__(4)
221 FUNC_MODIFIES(* dest_interp);
223 int pt_thread_run_2(PARROT_INTERP,
224 ARGOUT(PMC* dest_interp),
225 ARGIN(PMC* sub),
226 ARGIN(PMC *arg))
227 __attribute__nonnull__(1)
228 __attribute__nonnull__(2)
229 __attribute__nonnull__(3)
230 __attribute__nonnull__(4)
231 FUNC_MODIFIES(* dest_interp);
233 int pt_thread_run_3(PARROT_INTERP,
234 ARGOUT(PMC* dest_interp),
235 ARGIN(PMC* sub),
236 ARGIN(PMC *arg))
237 __attribute__nonnull__(1)
238 __attribute__nonnull__(2)
239 __attribute__nonnull__(3)
240 __attribute__nonnull__(4)
241 FUNC_MODIFIES(* dest_interp);
243 void pt_thread_wait_with(PARROT_INTERP, ARGMOD(Parrot_mutex *mutex))
244 __attribute__nonnull__(1)
245 __attribute__nonnull__(2)
246 FUNC_MODIFIES(*mutex);
248 void pt_thread_yield(void);
249 PARROT_CAN_RETURN_NULL
250 PMC * pt_transfer_sub(
251 ARGOUT(Parrot_Interp d),
252 ARGIN(Parrot_Interp s),
253 ARGIN(PMC *sub))
254 __attribute__nonnull__(1)
255 __attribute__nonnull__(2)
256 __attribute__nonnull__(3)
257 FUNC_MODIFIES(d);
259 #define ASSERT_ARGS_Parrot_shared_gc_block __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
260 PARROT_ASSERT_ARG(interp))
261 #define ASSERT_ARGS_Parrot_shared_gc_unblock __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
262 PARROT_ASSERT_ARG(interp))
263 #define ASSERT_ARGS_pt_add_to_interpreters __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
264 PARROT_ASSERT_ARG(interp))
265 #define ASSERT_ARGS_pt_clone_code __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
266 #define ASSERT_ARGS_pt_clone_globals __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
267 #define ASSERT_ARGS_pt_free_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
268 PARROT_ASSERT_ARG(interp))
269 #define ASSERT_ARGS_pt_gc_mark_root_finished __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
270 PARROT_ASSERT_ARG(interp))
271 #define ASSERT_ARGS_pt_gc_start_mark __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
272 PARROT_ASSERT_ARG(interp))
273 #define ASSERT_ARGS_pt_gc_stop_mark __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
274 PARROT_ASSERT_ARG(interp))
275 #define ASSERT_ARGS_pt_join_threads __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
276 PARROT_ASSERT_ARG(interp))
277 #define ASSERT_ARGS_pt_shared_fixup __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
278 PARROT_ASSERT_ARG(interp) \
279 , PARROT_ASSERT_ARG(pmc))
280 #define ASSERT_ARGS_pt_suspend_self_for_gc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
281 PARROT_ASSERT_ARG(interp))
282 #define ASSERT_ARGS_pt_thread_detach __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
283 #define ASSERT_ARGS_pt_thread_join __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
284 PARROT_ASSERT_ARG(parent))
285 #define ASSERT_ARGS_pt_thread_kill __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
286 #define ASSERT_ARGS_pt_thread_prepare_for_run __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
287 #define ASSERT_ARGS_pt_thread_run __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
288 PARROT_ASSERT_ARG(interp) \
289 , PARROT_ASSERT_ARG(dest_interp) \
290 , PARROT_ASSERT_ARG(sub))
291 #define ASSERT_ARGS_pt_thread_run_1 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
292 PARROT_ASSERT_ARG(interp) \
293 , PARROT_ASSERT_ARG(dest_interp) \
294 , PARROT_ASSERT_ARG(sub) \
295 , PARROT_ASSERT_ARG(arg))
296 #define ASSERT_ARGS_pt_thread_run_2 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
297 PARROT_ASSERT_ARG(interp) \
298 , PARROT_ASSERT_ARG(dest_interp) \
299 , PARROT_ASSERT_ARG(sub) \
300 , PARROT_ASSERT_ARG(arg))
301 #define ASSERT_ARGS_pt_thread_run_3 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
302 PARROT_ASSERT_ARG(interp) \
303 , PARROT_ASSERT_ARG(dest_interp) \
304 , PARROT_ASSERT_ARG(sub) \
305 , PARROT_ASSERT_ARG(arg))
306 #define ASSERT_ARGS_pt_thread_wait_with __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
307 PARROT_ASSERT_ARG(interp) \
308 , PARROT_ASSERT_ARG(mutex))
309 #define ASSERT_ARGS_pt_thread_yield __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
310 #define ASSERT_ARGS_pt_transfer_sub __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
311 PARROT_ASSERT_ARG(d) \
312 , PARROT_ASSERT_ARG(s) \
313 , PARROT_ASSERT_ARG(sub))
314 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
315 /* HEADERIZER END: src/thread.c */
317 #endif /* PARROT_THREAD_H_GUARD */
320 * Local variables:
321 * c-file-style: "parrot"
322 * End:
323 * vim: expandtab shiftwidth=4: