1 /* thread.h
2  *  Copyright (C) 2001-2012, Parrot Foundation.
3  *  Overview:
4  *     This is the api header for the thread primitives
5  *  Data Structure and Algorithms:
6  *  History:
7  *  Notes:
8  *  References:
9  */
10 
11 #ifndef PARROT_THREAD_H_GUARD
12 #define PARROT_THREAD_H_GUARD
13 
14 #include "parrot/parrot.h"
15 
16 #ifdef PARROT_HAS_THREADS
17 #  ifdef _WIN32
18 #    include "parrot/thr_windows.h"
19 #  else
20 #    include "parrot/thr_pthread.h"
21 #  endif
22 #else
23 #  include   "parrot/thr_none.h"
24 #endif /* PARROT_HAS_THREADS */
25 
26 #include "parrot/atomic.h"
27 
28 #define MAX_THREADS 16
29 
30 #ifndef YIELD
31 #  define YIELD
32 #endif /* YIELD */
33 
34 typedef enum {
35     THREAD_STATE_JOINABLE,             /* default */
36     THREAD_STATE_DETACHED     = 0x01,  /* i.e. non-joinable */
37     THREAD_STATE_JOINED       = 0x02,  /* JOIN was issued */
38     THREAD_STATE_FINISHED     = 0x04,  /* the thread function has ended */
39     THREAD_STATE_NOT_STARTED  = 0x08,  /* the thread wasn't started */
40     THREAD_STATE_SUSPENDED_GC = 0x10,  /* suspended for GC on request */
41     THREAD_STATE_GC_WAKEUP    = 0x20,  /* the thread is waiting on its condition
42                                            variable, and will do a GC run if
43                                            it is woken up and marked as suspended
44                                            for GC */
45     THREAD_STATE_SUSPEND_GC_REQUESTED = 0x40 /* the thread's event queue
46                                                  contains a suspend-for-GC event */
47 } thread_state_enum;
48 
49 
50 /*
51  * per interpreter thread data structure
52  */
53 typedef struct _Thread_data {
54     Parrot_thread       thread;          /* pthread_t or such */
55     INTVAL              state;
56     UINTVAL             tid;             /* 0.. n-1 idx in interp array */
57     Parrot_Interp       main_interp;
58 
59     /* for wr access to interpreter e.g. for GC
60      * if only used for GC the lock could be in the arena
61      * instead here, or in the interpreter, with negative size impact
62      * for the non-threaded case
63      */
64     Parrot_mutex interp_lock;
65 
66     /* for waking up the interpreter from various sorts
67      * of sleeping
68      */
69     Parrot_cond  interp_cond;
70 } Thread_data;
71 
72 #  define LOCK_INTERPRETER(interp) \
73     if ((interp)->thread_data) \
74         LOCK((interp)->thread_data->interp_lock)
75 #  define UNLOCK_INTERPRETER(interp) \
76     if ((interp)->thread_data) \
77         UNLOCK((interp)->thread_data->interp_lock)
78 
79 #  define INTERPRETER_LOCK_INIT(interp) \
80         do { \
81             MUTEX_INIT((interp)->thread_data->interp_lock); \
82             COND_INIT((interp)->thread_data->interp_cond); \
83         } while (0)
84 #  define INTERPRETER_LOCK_DESTROY(interp) \
85         do { \
86             MUTEX_DESTROY((interp)->thread_data->interp_lock); \
87             COND_DESTROY((interp)->thread_data->interp_cond); \
88         } while (0)
89 
90 /*
91  * this global mutex protects the list of interpreters
92  */
93 VAR_SCOPE Parrot_mutex    interpreter_array_mutex;
94 VAR_SCOPE Interp       ** interpreter_array;
95 VAR_SCOPE size_t          n_interpreters;
96 
97 typedef enum {
98     THREAD_GC_STAGE_NONE,
99     THREAD_GC_STAGE_MARK,
100     THREAD_GC_STAGE_SWEEP = THREAD_GC_STAGE_NONE
101 } thread_gc_stage_enum;
102 
103 typedef struct _Shared_gc_info {
104     thread_gc_stage_enum  gc_stage;
105     Parrot_cond           gc_cond;
106     int                   num_reached;
107 
108     Parrot_atomic_integer gc_block_level;
109 } Shared_gc_info;
110 
111 /* TODO use thread pools instead */
112 VAR_SCOPE Shared_gc_info *shared_gc_info;
113 
114 /* HEADERIZER BEGIN: src/thread.c */
115 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
116 
117 void Parrot_clone_code(Parrot_Interp d, Parrot_Interp s);
118 int Parrot_get_num_threads(PARROT_INTERP);
119 int Parrot_set_num_threads(PARROT_INTERP, INTVAL number_of_threads);
120 PARROT_CANNOT_RETURN_NULL
121 PMC * Parrot_thread_create(PARROT_INTERP, INTVAL type, INTVAL clone_flags)
122         __attribute__nonnull__(1);
123 
124 PARROT_CANNOT_RETURN_NULL
125 PMC* Parrot_thread_create_local_sub(PARROT_INTERP,
126     ARGIN(Parrot_Interp const thread),
127     ARGIN(PMC *pmc))
128         __attribute__nonnull__(1)
129         __attribute__nonnull__(2)
130         __attribute__nonnull__(3);
131 
132 PARROT_CANNOT_RETURN_NULL
133 PMC* Parrot_thread_create_local_task(PARROT_INTERP,
134     ARGIN(Parrot_Interp const thread_interp),
135     ARGIN(PMC *task))
136         __attribute__nonnull__(1)
137         __attribute__nonnull__(2)
138         __attribute__nonnull__(3);
139 
140 PARROT_CANNOT_RETURN_NULL
141 PMC* Parrot_thread_create_proxy(PARROT_INTERP,
142     ARGIN(Parrot_Interp const thread),
143     ARGIN(PMC *pmc))
144         __attribute__nonnull__(1)
145         __attribute__nonnull__(2)
146         __attribute__nonnull__(3);
147 
148 int Parrot_thread_get_free_threads_array_index(PARROT_INTERP);
149 PARROT_CANNOT_RETURN_NULL
150 Interp** Parrot_thread_get_threads_array(PARROT_INTERP);
151 
152 void Parrot_thread_init_threads_array(PARROT_INTERP)
153         __attribute__nonnull__(1);
154 
155 void Parrot_thread_insert_thread(PARROT_INTERP,
156     ARGIN(Interp* thread),
157     int index)
158         __attribute__nonnull__(2);
159 
160 PARROT_CAN_RETURN_NULL
161 PMC * Parrot_thread_make_local_copy(PARROT_INTERP,
162     ARGIN(Parrot_Interp from),
163     ARGIN(PMC *arg))
164         __attribute__nonnull__(1)
165         __attribute__nonnull__(2)
166         __attribute__nonnull__(3);
167 
168 void Parrot_thread_notify_thread(PARROT_INTERP)
169         __attribute__nonnull__(1);
170 
171 void Parrot_thread_notify_threads(PARROT_INTERP);
172 int Parrot_thread_run(PARROT_INTERP,
173     ARGMOD(PMC *thread_interp_pmc),
174     PMC *sub,
175     ARGIN_NULLOK(PMC *arg))
176         __attribute__nonnull__(1)
177         __attribute__nonnull__(2)
178         FUNC_MODIFIES(*thread_interp_pmc);
179 
180 void Parrot_thread_schedule_task(PARROT_INTERP,
181     ARGIN(Interp *thread_interp),
182     ARGIN(PMC *task))
183         __attribute__nonnull__(1)
184         __attribute__nonnull__(2)
185         __attribute__nonnull__(3);
186 
187 PARROT_CAN_RETURN_NULL
188 PMC * Parrot_thread_transfer_sub(
189     ARGOUT(Parrot_Interp destination),
190     ARGIN(Parrot_Interp source),
191     ARGIN(PMC *sub))
192         __attribute__nonnull__(1)
193         __attribute__nonnull__(2)
194         __attribute__nonnull__(3)
195         FUNC_MODIFIES(destination);
196 
197 void Parrot_thread_wait_for_notification(PARROT_INTERP)
198         __attribute__nonnull__(1);
199 
200 #define ASSERT_ARGS_Parrot_clone_code __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
201 #define ASSERT_ARGS_Parrot_get_num_threads __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
202 #define ASSERT_ARGS_Parrot_set_num_threads __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
203 #define ASSERT_ARGS_Parrot_thread_create __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
204        PARROT_ASSERT_ARG(interp))
205 #define ASSERT_ARGS_Parrot_thread_create_local_sub \
206      __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
207        PARROT_ASSERT_ARG(interp) \
208     , PARROT_ASSERT_ARG(thread) \
209     , PARROT_ASSERT_ARG(pmc))
210 #define ASSERT_ARGS_Parrot_thread_create_local_task \
211      __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
212        PARROT_ASSERT_ARG(interp) \
213     , PARROT_ASSERT_ARG(thread_interp) \
214     , PARROT_ASSERT_ARG(task))
215 #define ASSERT_ARGS_Parrot_thread_create_proxy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
216        PARROT_ASSERT_ARG(interp) \
217     , PARROT_ASSERT_ARG(thread) \
218     , PARROT_ASSERT_ARG(pmc))
219 #define ASSERT_ARGS_Parrot_thread_get_free_threads_array_index \
220      __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
221 #define ASSERT_ARGS_Parrot_thread_get_threads_array \
222      __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
223 #define ASSERT_ARGS_Parrot_thread_init_threads_array \
224      __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
225        PARROT_ASSERT_ARG(interp))
226 #define ASSERT_ARGS_Parrot_thread_insert_thread __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
227        PARROT_ASSERT_ARG(thread))
228 #define ASSERT_ARGS_Parrot_thread_make_local_copy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
229        PARROT_ASSERT_ARG(interp) \
230     , PARROT_ASSERT_ARG(from) \
231     , PARROT_ASSERT_ARG(arg))
232 #define ASSERT_ARGS_Parrot_thread_notify_thread __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
233        PARROT_ASSERT_ARG(interp))
234 #define ASSERT_ARGS_Parrot_thread_notify_threads __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
235 #define ASSERT_ARGS_Parrot_thread_run __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
236        PARROT_ASSERT_ARG(interp) \
237     , PARROT_ASSERT_ARG(thread_interp_pmc))
238 #define ASSERT_ARGS_Parrot_thread_schedule_task __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
239        PARROT_ASSERT_ARG(interp) \
240     , PARROT_ASSERT_ARG(thread_interp) \
241     , PARROT_ASSERT_ARG(task))
242 #define ASSERT_ARGS_Parrot_thread_transfer_sub __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
243        PARROT_ASSERT_ARG(destination) \
244     , PARROT_ASSERT_ARG(source) \
245     , PARROT_ASSERT_ARG(sub))
246 #define ASSERT_ARGS_Parrot_thread_wait_for_notification \
247      __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
248        PARROT_ASSERT_ARG(interp))
249 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
250 /* HEADERIZER END: src/thread.c */
251 
252 #define Parrot_thread_maybe_create_proxy(i, thread, pmc) ( \
253         (pmc)->vtable->base_type == enum_class_Proxy \
254         ? (PARROT_PROXY(pmc)->interp == (thread) ? PARROT_PROXY(pmc)->target : (pmc)) \
255         : Parrot_thread_create_proxy((i), (thread), (pmc)))
256 
257 #endif /* PARROT_THREAD_H_GUARD */
258 
259 /*
260  * Local variables:
261  *   c-file-style: "parrot"
262  * End:
263  * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
264  */
265