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