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