1 /* Part of SWI-Prolog
2
3 Author: Jan Wielemaker
4 E-mail: J.Wielemaker@vu.nl
5 WWW: http://www.swi-prolog.org
6 Copyright (c) 1999-2019, University of Amsterdam
7 VU University Amsterdam
8 CWI, Amsterdam
9 All rights reserved.
10
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
13 are met:
14
15 1. Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17
18 2. Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in
20 the documentation and/or other materials provided with the
21 distribution.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #ifndef PL_THREAD_H_DEFINED
38 #define PL_THREAD_H_DEFINED
39
40 #ifdef O_PLMT
41 #include <pthread.h>
42
43 #ifdef HAVE_SEMA_INIT
44 #include <synch.h>
45 #endif
46
47 #ifndef __WINDOWS__
48 #define SIG_ALERT SIGUSR2
49 #endif
50
51 #if defined(__linux__) || defined(__CYGWIN__)
52 #define PID_IDENTIFIES_THREAD 1
53 #endif
54
55 #define GCREQUEST_AGC 0x01 /* GD->thread.gc.requests */
56 #define GCREQUEST_CGC 0x02
57 #define GCREQUEST_ABORT 0x04
58
59 #define EXIT_REQ_PROCESS 1
60 #define EXIT_REQ_THREAD 2
61
62 typedef enum
63 { LDATA_IDLE = 0,
64 LDATA_SIGNALLED,
65 LDATA_ANSWERING,
66 LDATA_ANSWERED
67 } ldata_status_t;
68
69 #define THREAD_STATUS_INVALID(s) ((int)(s) < (int)PL_THREAD_RUNNING)
70
71 typedef enum
72 { PL_THREAD_UNUSED = 0, /* no thread on this slot */
73 PL_THREAD_RESERVED, /* allocated but not yet created */
74 PL_THREAD_JOINED, /* just joined */
75 /* normal states */
76 PL_THREAD_RUNNING, /* a normally running one */
77 PL_THREAD_EXITED, /* died with thread_exit/1 */
78 PL_THREAD_SUCCEEDED, /* finished with Yes */
79 PL_THREAD_FAILED, /* finished with No */
80 PL_THREAD_EXCEPTION, /* finished with exception */
81 PL_THREAD_NOMEM, /* couldn't start due no-memory */
82 PL_THREAD_CREATED, /* just created */
83 } thread_status;
84
85 typedef struct _PL_thread_info_t
86 { int pl_tid; /* Prolog thread id */
87 size_t stack_limit; /* Stack sizes */
88 size_t table_space; /* Max size for local tables */
89 size_t c_stack_size; /* system (C-) stack */
90 rc_cancel (*cancel)(int id); /* cancel function */
91 unsigned short open_count; /* for PL_thread_detach_engine() */
92 unsigned detached : 1; /* detached thread */
93 unsigned debug : 1; /* thread can be debugged */
94 unsigned in_exit_hooks : 1; /* TRUE: running exit hooks */
95 unsigned has_tid : 1; /* TRUE: tid = valid */
96 unsigned is_engine : 1; /* TRUE: created as engine */
97 thread_status status; /* PL_THREAD_* */
98 pthread_t tid; /* Thread identifier */
99 #ifdef PID_IDENTIFIES_THREAD
100 pid_t pid; /* for identifying */
101 #endif
102 #ifdef __WINDOWS__
103 DWORD w32id; /* Win32 thread HANDLE */
104 #endif
105 struct PL_local_data *thread_data; /* The thread-local data */
106 module_t module; /* Module for starting goal */
107 record_t goal; /* Goal to start thread */
108 record_t return_value; /* Value (term) returned */
109 atom_t symbol; /* thread_handle symbol */
110 struct _PL_thread_info_t *next_free; /* Next in free list */
111
112 /* lock-free access to data */
113 struct
114 { KVS kvs; /* current hash-table map accessed */
115 AtomTable atom_table; /* current atom-table accessed */
116 Atom * atom_bucket; /* current atom bucket-list accessed */
117 FunctorTable functor_table; /* current atom-table accessed */
118 Definition predicate; /* current predicate walked */
119 struct PL_local_data *ldata; /* current ldata accessed */
120 } access;
121 } PL_thread_info_t;
122
123
124 #define TH_IS_INTERACTOR 0x0001 /* Thread is an interactor (engine) */
125 #define TH_INTERACTOR_NOMORE 0x0002 /* No more answers */
126 #define TH_INTERACTOR_DONE 0x0004 /* Answered last */
127
128 typedef struct thread_handle
129 { PL_thread_info_t *info; /* represented engine */
130 atom_t symbol; /* associated symbol */
131 atom_t alias; /* alias name of the thread */
132 int engine_id; /* numeric engine id */
133 int flags; /* symbol flags */
134 struct
135 { qid_t query; /* Query handle */
136 term_t argv; /* Arguments */
137 record_t package; /* Exchanged term */
138 simpleMutex *mutex; /* Sync access */
139 atom_t thread; /* Associated thread */
140 } interactor;
141 struct thread_handle *next_free; /* Free for GC */
142 } thread_handle;
143
144
145 #define QTYPE_THREAD 0
146 #define QTYPE_QUEUE 1
147
148 typedef struct message_queue
149 { simpleMutex mutex; /* Message queue mutex */
150 #ifdef __WINDOWS__
151 CONDITION_VARIABLE cond_var;
152 CONDITION_VARIABLE drain_var;
153 #else
154 pthread_cond_t cond_var; /* condvar for reading */
155 pthread_cond_t drain_var; /* condvar for writing */
156 #endif
157 struct thread_message *head; /* Head of message queue */
158 struct thread_message *tail; /* Tail of message queue */
159 uint64_t sequence_next; /* next for sequence id */
160 word id; /* Id of the queue */
161 size_t size; /* # terms in queue */
162 size_t max_size; /* Max # terms in queue */
163 int waiting; /* # waiting threads */
164 int waiting_var; /* # waiting with unbound */
165 int wait_for_drain; /* # threads waiting for write */
166 unsigned anonymous : 1; /* <message_queue>(0x...) */
167 unsigned initialized : 1; /* Queue is initialised */
168 unsigned destroyed : 1; /* Thread is being destroyed */
169 unsigned type : 2; /* QTYPE_* */
170 #ifdef O_ATOMGC
171 simpleMutex gc_mutex; /* Atom GC scanning sychronization */
172 #endif
173 } message_queue;
174
175 typedef struct pl_mutex
176 { pthread_mutex_t mutex; /* the system mutex */
177 int count; /* lock count */
178 int owner; /* integer id of owner */
179 atom_t id; /* id of the mutex */
180 unsigned anonymous : 1; /* <mutex>(0x...) */
181 unsigned initialized : 1; /* Mutex is initialized */
182 unsigned destroyed : 1; /* Mutex is destroyed */
183 unsigned auto_destroy : 1; /* asked to destroy */
184 } pl_mutex;
185
186 #define ALERT_QUEUE_RD 1
187 #define ALERT_QUEUE_WR 2
188
189 typedef struct alert_channel
190 { int type; /* Type of channel */
191 union
192 { message_queue *queue;
193 } obj;
194 } alert_channel;
195
196 #define PL_THREAD_MAGIC 0x2737234f
197
198 extern counting_mutex _PL_mutexes[]; /* Prolog mutexes */
199
200 #define L_MISC 0
201 #define L_ALLOC 1
202 #define L_REHASH_ATOMS 2
203 #define L_FLAG 3
204 #define L_FUNCTOR 4
205 #define L_RECORD 5
206 #define L_THREAD 6
207 #define L_MUTEX 7
208 #define L_PREDICATE 8
209 #define L_MODULE 9
210 #define L_SRCFILE 10
211 #define L_TABLE 11
212 #define L_BREAK 12
213 #define L_FILE 13
214 #define L_SEETELL 14
215 #define L_PLFLAG 15
216 #define L_OP 16
217 #define L_INIT 17
218 #define L_TERM 18
219 #define L_FOREIGN 19
220 #define L_OS 20
221 #define L_LOCALE 21
222 #define L_SORTR 22
223 #define L_UMUTEX 23
224 #define L_INIT_ATOMS 24
225 #define L_CGCGEN 25
226 #define L_EVHOOK 26
227 #define L_OSDIR 27
228 #define L_ALERT 28
229 #ifdef __WINDOWS__
230 #define L_DDE 29
231 #define L_CSTACK 30
232 #endif
233
234 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
235 The IF_MT(id, g) macro is used to bypass mutexes if threading is
236 disabled. We cannot do this for the L_THREAD mutex however as we need to
237 control when threads can be created.
238
239 We assume id == L_THREAD is optimized away if id is known at
240 compile-time
241 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
242
243 #define IF_MT(id, g) if ( id == L_THREAD || GD->thread.enabled ) g
244
245 static inline void
countingMutexLock(counting_mutex * cm)246 countingMutexLock(counting_mutex *cm)
247 {
248 #if O_CONTENTION_STATISTICS
249 if ( !simpleMutexTryLock(&cm->mutex) )
250 { cm->collisions++;
251 simpleMutexLock(&cm->mutex);
252 }
253 #else
254 simpleMutexLock(&cm->mutex);
255 #endif
256
257 cm->count++;
258 cm->lock_count++;
259 }
260
261 static inline void
countingMutexUnlock(counting_mutex * cm)262 countingMutexUnlock(counting_mutex *cm)
263 { assert(cm->lock_count > 0);
264 cm->lock_count--;
265 simpleMutexUnlock(&cm->mutex);
266 }
267
268 #ifdef O_DEBUG_MT
269 #define PL_LOCK(id) \
270 do { Sdprintf("[%s] %s:%d: LOCK(%s)\n", \
271 threadName(0), \
272 __BASE_FILE__, __LINE__, #id); \
273 IF_MT(id, countingMutexLock(&_PL_mutexes[id])); \
274 } while(0)
275 #define PL_UNLOCK(id) \
276 do { Sdprintf("[%s] %s:%d: UNLOCK(%s)\n", \
277 threadName(0), \
278 __BASE_FILE__, __LINE__, #id); \
279 IF_MT(id, countingMutexUnlock(&_PL_mutexes[id])); \
280 } while(0)
281 #else
282 #define PL_LOCK(id) IF_MT(id, countingMutexLock(&_PL_mutexes[id]))
283 #define PL_UNLOCK(id) IF_MT(id, countingMutexUnlock(&_PL_mutexes[id]))
284 #endif
285
286 #define LOCKDEF(def) PL_LOCK(L_PREDICATE)
287 #define UNLOCKDEF(def) PL_UNLOCK(L_PREDICATE)
288
289 #define LOCKMODULE(module) countingMutexLock((module)->mutex)
290 #define UNLOCKMODULE(module) countingMutexUnlock((module)->mutex)
291
292 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
293 Thread-local data
294
295 All thread-local data is combined in one structure defined in
296 pl-global.h. If Prolog is compiled for single-threading this is a simple
297 global variable and the macro LD is defined to pick up the address of
298 this variable. In multithreaded context, POSIX pthread_getspecific() is
299 used to get separate versions for each thread. Functions uisng LD often
300 may wish to write:
301
302 <header>
303 { GET_LD
304 #undef LD
305 #define LD LOCAL_LD
306 ...
307
308 #undef LD
309 #define LD GLOBAL_LD
310 }
311 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
312
313 /*******************************
314 * NATIVE THREAD-LOCAL DATA *
315 *******************************/
316
317 #ifdef HAVE___THREAD
318 extern __thread PL_local_data_t *GLOBAL_LD;
319 #define TLD_set_LD(v) (GLOBAL_LD = (v))
320 #else
321
322 #ifdef __WINDOWS__
323 typedef DWORD TLD_KEY;
324
325 #define TLD_alloc(p) (*(p) = TlsAlloc())
326 #define TLD_get(p) TlsGetValue((p))
327 #define TLD_set(p, v) TlsSetValue((p), (v))
328 #define TLD_free(p) TlsFree(p);
329
330 #else
331 typedef pthread_key_t TLD_KEY;
332
333 #define TLD_alloc(p) pthread_key_create(p, NULL)
334 #define TLD_get(p) pthread_getspecific(p)
335 #define TLD_set(p, v) pthread_setspecific((p), (v))
336 #define TLD_free(p) pthread_key_delete(p)
337 #endif
338
339 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
340 If available, use GCC's __attribute((const)) to tell the compiler it may
341 choose to store the result of LD is a local variable.
342 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
343
344 extern TLD_KEY PL_ldata; /* key to local data */
345
346 #define GLOBAL_LD ((PL_local_data_t *)TLD_get(PL_ldata))
347 #define TLD_set_LD(v) TLD_set(PL_ldata, v)
348 #endif /*HAVE___THREAD*/
349
350
351 /*******************************
352 * WINDOWS *
353 *******************************/
354
355 #define WM_SIGNALLED (WM_USER+4201) /* how to select a good number!? */
356
357
358 /*******************************
359 * FUNCTIONS *
360 *******************************/
361
362 COMMON(int) exitPrologThreads(void);
363 COMMON(bool) aliasThread(int tid, atom_t type, atom_t name);
364 COMMON(word) pl_thread_create(term_t goal, term_t id,
365 term_t options);
366 COMMON(word) pl_thread_exit(term_t retcode);
367 COMMON(foreign_t) pl_thread_signal(term_t thread, term_t goal);
368
369 COMMON(foreign_t) pl_thread_at_exit(term_t goal);
370 extern int PL_thread_self(void);
371
372 COMMON(const char *) threadName(int id);
373 COMMON(void) executeThreadSignals(int sig);
374 COMMON(foreign_t) pl_attach_xterm(term_t in, term_t out);
375 COMMON(int) attachConsole(void);
376 COMMON(Definition) localiseDefinition(Definition def);
377 COMMON(LocalDefinitions) new_ldef_vector(void);
378 COMMON(void) free_ldef_vector(LocalDefinitions ldefs);
379 COMMON(void) cleanupLocalDefinitions(PL_local_data_t *ld);
380 COMMON(void) destroyLocalDefinitions(Definition def);
381 int PL_mutex_lock(struct pl_mutex *m);
382 int PL_mutex_unlock(struct pl_mutex *m);
383 int PL_thread_raise(int tid, int sig);
384 COMMON(void) cleanupThreads(void);
385 COMMON(intptr_t) system_thread_id(PL_thread_info_t *info);
386 COMMON(double) ThreadCPUTime(PL_local_data_t *ld, int which);
387 COMMON(void) get_current_timespec(struct timespec *time);
388 COMMON(void) carry_timespec_nanos(struct timespec *time);
389
390 /*******************************
391 * GLOBAL GC SUPPORT *
392 *******************************/
393
394 COMMON(void) forThreadLocalDataUnsuspended(
395 void (*func)(struct PL_local_data *),
396 unsigned flags);
397 COMMON(void) resumeThreads(void);
398 COMMON(void) markAtomsMessageQueues(void);
399 COMMON(void) markAtomsThreadMessageQueue(PL_local_data_t *ld);
400
401 #define acquire_ldata(info) acquire_ldata__LD(info PASS_LD)
402 #define release_ldata(ld) (LD->thread.info->access.ldata = NULL)
403
404 /*******************************
405 * CONDITION VARIABLES *
406 *******************************/
407
408 #define CV_READY 0 /* was signalled */
409 #define CV_MAYBE 1 /* might be signalled */
410 #define CV_TIMEDOUT 2 /* timed out */
411 #define CV_INTR 3 /* interrupted */
412
413 #ifdef __WINDOWS__
414
415 COMMON(int) cv_timedwait(message_queue *queue,
416 CONDITION_VARIABLE *cv,
417 CRITICAL_SECTION *external_mutex,
418 struct timespec *deadline);
419
420 #define cv_broadcast(cv) WakeAllConditionVariable(cv)
421 #define cv_signal(cv) WakeConditionVariable(cv)
422 #define cv_init(cv,p) InitializeConditionVariable(cv)
423 #define cv_destroy(cv) (void)cv
424
425 #else
426
427 COMMON(int) cv_timedwait(message_queue *queue,
428 pthread_cond_t *cv,
429 pthread_mutex_t *external_mutex,
430 struct timespec *deadline);
431
432 #define cv_broadcast(cv) pthread_cond_broadcast(cv)
433 #define cv_signal(cv) pthread_cond_signal(cv)
434 #define cv_init(cv,p) pthread_cond_init(cv,p)
435 #define cv_destroy(cv) pthread_cond_destroy(cv)
436
437 #endif /* __WINDOWS__ */
438
439 #define cv_wait(cv, m) cv_timedwait(NULL, cv, m, NULL)
440
441
442 #else /*O_PLMT, end of threading-stuff */
443
444 /*******************************
445 * NON-THREAD STUFF *
446 *******************************/
447
448 #ifdef O_MULTIPLE_ENGINES
449
450 #define GLOBAL_LD PL_current_engine_ptr
451
452 #else /*O_MULTIPLE_ENGINES*/
453
454 #define GLOBAL_LD (&PL_local_data)
455
456 #endif /*O_MULTIPLE_ENGINES*/
457
458 #define PL_LOCK(id)
459 #define PL_UNLOCK(id)
460
461 #define LOCKDEF(def)
462 #define UNLOCKDEF(def)
463 #define UNLOCKDYNDEF(def)
464 #define LOCKMODULE(module)
465 #define UNLOCKMODULE(module)
466
467 #define acquire_ldata(ld) (ld)
468 #define release_ldata(ld) (void)0
469
470 COMMON(double) ThreadCPUTime(PL_local_data_t *ld, int which);
471
472 #endif /*O_PLMT*/
473
474 /*******************************
475 * COMMON *
476 *******************************/
477
478 typedef struct
479 { functor_t functor; /* functor of property */
480 int (*function)(); /* function to generate */
481 } tprop;
482
483 COMMON(int) get_prop_def(term_t t, atom_t expected,
484 const tprop *list, const tprop **def);
485 COMMON(void) initPrologThreads(void);
486 COMMON(int) pl_atom_table_in_use(AtomTable atom_table);
487 COMMON(int) pl_atom_bucket_in_use(Atom *atom_bucket);
488 COMMON(Atom**) pl_atom_buckets_in_use(void);
489 COMMON(Definition*) predicates_in_use(void);
490 COMMON(int) pl_functor_table_in_use(FunctorTable functor_table);
491 COMMON(int) pl_kvs_in_use(KVS kvs);
492 COMMON(definition_ref*) pushPredicateAccessObj(Definition def ARG_LD);
493 COMMON(void) popPredicateAccess__LD(Definition def ARG_LD);
494 COMMON(size_t) popNPredicateAccess__LD(size_t n ARG_LD);
495 COMMON(void) markAccessedPredicates(PL_local_data_t *ld);
496 COMMON(int) cgc_thread_stats(cgc_stats *stats ARG_LD);
497 COMMON(int) signalGCThread(int sig);
498 COMMON(int) isSignalledGCThread(int sig ARG_LD);
499
500 #endif /*PL_THREAD_H_DEFINED*/
501