1 # This file is part of NIT (http://www.nitlanguage.org).
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Main POSIX threads support and intro the classes `Thread`, `Mutex` and `Barrier`
19 cflags
"-pthread -Wno-unknown-attributes"
22 new_annotation threaded
28 # Nity part at the bottom of the module.
38 // TODO protect with: #ifdef WITH_LIBGC
39 // We might have to add the next line to gc_chooser.c too, especially
40 // if we get an error like "thread not registered with GC".
42 #include "TargetConditionals.h"
43 #if TARGET_OS_IPHONE == 1
48 #if !defined(__ANDROID__) && !defined(IOS)
56 # `NativePthread` for running thread
57 private fun native_pthread_self
: NativePthread `{
58 pthread_t *id = malloc(sizeof(pthread_t));
63 private var self_thread_key
= new NativePthreadKey
65 private var main_thread_cache
: nullable MainThread = null
66 private var main_thread_mutex
= new Mutex
68 # Handle to the program's main thread
69 fun main_thread
: MainThread
71 var cache
= main_thread_cache
72 if cache
!= null then return cache
74 main_thread_mutex
.lock
76 # Recheck if cache has been updated since lock has been unlocked/locked
77 cache
= main_thread_cache
79 main_thread_mutex
.unlock
83 # Create a `MainThread` exactly once
84 var thread
= new MainThread
85 thread
.native
= sys
.native_pthread_self
86 main_thread_cache
= thread
88 main_thread_mutex
.unlock
95 extern class AtomicInt in "C" `{ int* `}
97 int
* v
= malloc
(sizeof
(int
));
101 # Get the value and increment it by `i
`
102 fun get_and_increment_by(i: Int): Int `{
103 return __sync_fetch_and_add
(self, i
);
106 # Get the value and decrement it by `i
`
107 fun get_and_decrement_by(i: Int): Int `{
108 return __sync_fetch_and_sub
(self, i
);
111 # Get the value and increment it
112 fun get_and_increment: Int `{
113 return __sync_fetch_and_add
(self, 1);
116 # Get the value and decrement it
117 fun get_and_decrement: Int `{
118 return __sync_fetch_and_sub
(self, 1);
121 # Increment by `i
` and get the new value
122 fun increment_by_and_get(i: Int): Int `{
123 return __sync_add_and_fetch
(self, i
);
126 # Decrement by `i
` and get the new value
127 fun decrement_by_and_get(i: Int): Int `{
128 return __sync_sub_and_fetch
(self, i
);
131 # Increment the value and get the new one
132 fun increment_and_get: Int `{
133 return __sync_add_and_fetch
(self, 1);
136 # Decrement the value and get the new one
137 fun decrement_and_get: Int `{
138 return __sync_sub_and_fetch
(self,1);
141 # Get the current value
148 private extern class NativePthread in "C" `{ pthread_t * `}
150 new create
(nit_thread
: Thread) import Thread.main_intern
`{
152 pthread_attr_init(&attr);
155 int r = pthread_create(&thread, &attr, (void * (*)(void *))&Thread_main_intern, nit_thread);
158 pthread_t *pthread = malloc(sizeof(pthread_t));
159 memmove(pthread, &thread, sizeof(pthread_t));
165 new create_ex
(nit_thread
: Thread, attr
: NativePthreadAttr) import Thread.main_intern
`{
167 int r = pthread_create(&thread, attr, (void * (*)(void *))&Thread_main_intern, nit_thread);
170 pthread_t *pthread = malloc(sizeof(pthread_t));
171 memmove(pthread, &thread, sizeof(pthread_t));
177 fun join
: nullable Object `{
179 pthread_join(*self, &thread_return);
180 if(thread_return == NULL) thread_return = null_Object();
181 return (nullable_Object)thread_return;
184 fun equal
(other
: NativePthread): Bool `{ return pthread_equal(*self, *other); `}
186 fun kill(signal: Int): Int `{ return pthread_kill(*self, (int)signal); `}
189 private extern class NativePthreadAttr in "C" `{ pthread_attr_t * `}
192 int r
= pthread_attr_init
(&attr
);
194 pthread_attr_t
*pattr
= malloc
(sizeof
(pthread_attr_t
));
195 memmove
(pattr
, &attr
, sizeof
(pthread_attr_t
));
202 pthread_attr_destroy
(self);
205 # Most features of this class are still TODO
207 # * pthread_attr_setaffinity_np(3)
208 # * pthread_attr_setdetachstate
209 # * pthread_attr_setguardsize
210 # * pthread_attr_setinheritsched
211 # * pthread_attr_setschedparam
212 # * pthread_attr_setschedpolicy
213 # * pthread_attr_setscope
214 # * pthread_attr_setstack
215 # * pthread_attr_setstackaddr
216 # * pthread_attr_setstacksize
219 private extern class NativePthreadMutex in "C" `{ pthread_mutex_t * `}
220 new (attr
: NativePthreadMutexAttr) `{
221 pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t));
222 int r = pthread_mutex_init(mutex, attr);
230 fun destroy
`{ pthread_mutex_destroy(self); `}
232 fun lock `{ pthread_mutex_lock(self); `}
233 fun try_lock
: Bool `{ return pthread_mutex_trylock(self); `}
234 fun unlock `{ pthread_mutex_unlock(self); `}
237 private extern class NativePthreadMutexAttr in "C" `{ pthread_mutexattr_t * `}
239 pthread_mutexattr_t
*attr
= malloc
(sizeof
(pthread_mutexattr_t
));
240 int r
= pthread_mutexattr_init
(attr
);
248 fun destroy `{ pthread_mutexattr_destroy(self); `}
250 fun set_type_normal
`{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_NORMAL); `}
251 fun set_type_recursive `{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_RECURSIVE); `}
252 fun set_type_errorcheck
`{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_ERRORCHECK); `}
254 # pthread_mutexattr_setpshared
255 # pthread_mutexattr_setprotocol
256 # pthread_mutexattr_setproceiling
257 # pthread_mutexattr_setrobust_np
260 private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
262 pthread_key_t *key = malloc(sizeof(pthread_key_t));
263 int r = pthread_key_create(key, NULL);
271 fun get
: nullable Object `{
272 void *val = pthread_getspecific(*self);
273 if (val == NULL) val = null_Object();
277 fun set
(val
: nullable Object) `{
278 pthread_setspecific(*self, val);
282 private extern class NativePthreadCond in "C" `{ pthread_cond_t * `}
285 int r
= pthread_cond_init
(&cond
, NULL);
287 pthread_cond_t
*pcond
= malloc
(sizeof
(pthread_cond_t
));
288 memmove
(pcond
, &cond
, sizeof
(pthread_cond_t
));
294 fun destroy `{ pthread_cond_destroy(self); `}
296 fun signal
: Int `{ return pthread_cond_signal(self); `}
298 fun broadcast `{ pthread_cond_broadcast(self); `}
300 fun wait
(mutex
: NativePthreadMutex) `{ pthread_cond_wait(self, mutex); `}
306 # Cannot be extracted from this module because of the callback from C to `Thread::run
`
311 # Instances of this class are each used to launch and control a thread.
312 abstract class Thread
315 # Type returned by `main
`
316 type E : nullable Object
318 private var native: nullable NativePthread = null
320 # Is this thread finished ? True when main returned
323 # Main method of this thread
325 # The returned valued is passed to the caller of `join
`.
326 fun main: E do return null
328 private fun main_intern: E
330 # Register thread local data
331 sys.self_thread_key.set self
337 # Start executing this thread
339 # Will launch `main
` on a different thread.
342 if native != null then return
343 native = new NativePthread.create(self)
346 # Join this thread to the calling thread
348 # Blocks until the method `main
` returns or the target thread calls
349 # `Sys::thread_exit
`. Returns the object returned from the other thread.
351 # Stats the thread if now already done by a call to `start
`.
354 if native == null then start
362 if native == null then return
368 # The main thread of the program
375 # Exit current thread and return `value
` to caller of `Thread::join
`
376 fun exit_thread(value: nullable Object) `{ pthread_exit(value); `}
378 # Returns the handle to the running `Thread`
381 var key
= sys
.self_thread_key
384 # This is the original thread, get `Sys::main_thread` and store it
385 var thread
= sys
.main_thread
390 assert val
isa Thread
394 # Mutual exclusion synchronization tool
396 # Instances of this class can only be acquired by a single thread at any one
397 # point in time. Uses the recursive protocol so they can be locked many time by
398 # the same thread, must then be unlocked as many time.
402 private var native
: nullable NativePthreadMutex is noinit
406 var attr
= new NativePthreadMutexAttr
407 attr
.set_type_recursive
408 native
= new NativePthreadMutex(attr
)
413 # Acquire this lock, wait until it is available
414 fun lock
do native
.lock
416 # Acquire this lock only if it is available
418 # Returns `true` if the lock has been acquired.
419 fun try_lock
: Bool do return native
.try_lock
421 # Release this lock, unblocking all callers of `lock`
422 fun unlock
do native
.unlock
426 var native
= self.native
427 if native
!= null then
437 super FinalizableOnce
439 private var native
= new NativePthreadCond
442 redef fun finalize_once
do native
.destroy
444 # Signal at least one thread waiting to wake up
445 fun signal
: Int do return native
.signal
447 # Signal all the waiting threads to wake up
448 fun broadcast
do native
.broadcast
450 # Make the current thread waiting for a signal ( `mutex` should be locked)
451 fun wait
(mutex
: Mutex) do native
.wait
(mutex
.native
.as(not null))
454 # Barrier synchronization tool
456 # Ensures that `count` threads call and block on `wait` before releasing them.
460 private var mutex
= new Mutex
461 private var cond
: nullable NativePthreadCond = new NativePthreadCond
463 # Number of threads that must be waiting for `wait` to unblock
466 private var threads_waiting
= 0
468 # Wait at this barrier and block until there are a `count` threads waiting
473 if threads_waiting
== count
then
477 cond
.wait
(mutex
.native
.as(not null))
493 # Print `object` and '\n' with the same system call
494 redef fun print
(object
)
496 sys
.stdout
.write
(object
.to_s
+"\n")