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".
47 # `NativePthread` for running thread
48 private fun native_pthread_self
: NativePthread `{
49 pthread_t *id = malloc(sizeof(pthread_t));
54 private var self_thread_key
= new NativePthreadKey
56 private var main_thread_cache
: nullable MainThread = null
57 private var main_thread_mutex
= new Mutex
59 # Handle to the program's main thread
60 fun main_thread
: MainThread
62 var cache
= main_thread_cache
63 if cache
!= null then return cache
65 main_thread_mutex
.lock
67 # Recheck if cache has been updated since lock has been unlocked/locked
68 cache
= main_thread_cache
70 main_thread_mutex
.unlock
74 # Create a `MainThread` exactly once
75 var thread
= new MainThread
76 thread
.native
= sys
.native_pthread_self
77 main_thread_cache
= thread
79 main_thread_mutex
.unlock
86 extern class AtomicInt in "C" `{ int* `}
88 int
* v
= malloc
(sizeof
(int
));
92 # Get the value and increment it by `i
`
93 fun get_and_increment_by(i: Int): Int `{
94 return __sync_fetch_and_add
(self, i
);
97 # Get the value and decrement it by `i
`
98 fun get_and_decrement_by(i: Int): Int `{
99 return __sync_fetch_and_sub
(self, i
);
102 # Get the value and increment it
103 fun get_and_increment: Int `{
104 return __sync_fetch_and_add
(self, 1);
107 # Get the value and decrement it
108 fun get_and_decrement: Int `{
109 return __sync_fetch_and_sub
(self, 1);
112 # Increment by `i
` and get the new value
113 fun increment_by_and_get(i: Int): Int `{
114 return __sync_add_and_fetch
(self, i
);
117 # Decrement by `i
` and get the new value
118 fun decrement_by_and_get(i: Int): Int `{
119 return __sync_sub_and_fetch
(self, i
);
122 # Increment the value and get the new one
123 fun increment_and_get: Int `{
124 return __sync_add_and_fetch
(self, 1);
127 # Decrement the value and get the new one
128 fun decrement_and_get: Int `{
129 return __sync_sub_and_fetch
(self,1);
132 # Get the current value
139 private extern class NativePthread in "C" `{ pthread_t * `}
141 new create
(nit_thread
: Thread) import Thread.main_intern
`{
143 pthread_attr_init(&attr);
146 int r = pthread_create(&thread, &attr, (void * (*)(void *))&Thread_main_intern, nit_thread);
149 pthread_t *pthread = malloc(sizeof(pthread_t));
150 memmove(pthread, &thread, sizeof(pthread_t));
156 new create_ex
(nit_thread
: Thread, attr
: NativePthreadAttr) import Thread.main_intern
`{
158 int r = pthread_create(&thread, attr, (void * (*)(void *))&Thread_main_intern, nit_thread);
161 pthread_t *pthread = malloc(sizeof(pthread_t));
162 memmove(pthread, &thread, sizeof(pthread_t));
168 fun join
: nullable Object `{
170 pthread_join(*self, &thread_return);
171 if(thread_return == NULL) thread_return = null_Object();
172 return (nullable_Object)thread_return;
175 fun equal
(other
: NativePthread): Bool `{ return pthread_equal(*self, *other); `}
177 fun kill(signal: Int): Int `{ return pthread_kill(*self, (int)signal); `}
180 private extern class NativePthreadAttr in "C" `{ pthread_attr_t * `}
183 int r
= pthread_attr_init
(&attr
);
185 pthread_attr_t
*pattr
= malloc
(sizeof
(pthread_attr_t
));
186 memmove
(pattr
, &attr
, sizeof
(pthread_attr_t
));
193 pthread_attr_destroy
(self);
196 # Most features of this class are still TODO
198 # * pthread_attr_setaffinity_np(3)
199 # * pthread_attr_setdetachstate
200 # * pthread_attr_setguardsize
201 # * pthread_attr_setinheritsched
202 # * pthread_attr_setschedparam
203 # * pthread_attr_setschedpolicy
204 # * pthread_attr_setscope
205 # * pthread_attr_setstack
206 # * pthread_attr_setstackaddr
207 # * pthread_attr_setstacksize
210 private extern class NativePthreadMutex in "C" `{ pthread_mutex_t * `}
211 new (attr
: NativePthreadMutexAttr) `{
212 pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t));
213 int r = pthread_mutex_init(mutex, attr);
221 fun destroy
`{ pthread_mutex_destroy(self); `}
223 fun lock `{ pthread_mutex_lock(self); `}
224 fun try_lock
: Bool `{ return pthread_mutex_trylock(self); `}
225 fun unlock `{ pthread_mutex_unlock(self); `}
228 private extern class NativePthreadMutexAttr in "C" `{ pthread_mutexattr_t * `}
230 pthread_mutexattr_t
*attr
= malloc
(sizeof
(pthread_mutexattr_t
));
231 int r
= pthread_mutexattr_init
(attr
);
239 fun destroy `{ pthread_mutexattr_destroy(self); `}
241 fun set_type_normal
`{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_NORMAL); `}
242 fun set_type_recursive `{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_RECURSIVE); `}
243 fun set_type_errorcheck
`{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_ERRORCHECK); `}
245 # pthread_mutexattr_setpshared
246 # pthread_mutexattr_setprotocol
247 # pthread_mutexattr_setproceiling
248 # pthread_mutexattr_setrobust_np
251 private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
253 pthread_key_t *key = malloc(sizeof(pthread_key_t));
254 int r = pthread_key_create(key, NULL);
262 fun get
: nullable Object `{
263 void *val = pthread_getspecific(*self);
264 if (val == NULL) val = null_Object();
268 fun set
(val
: nullable Object) `{
269 pthread_setspecific(*self, val);
273 private extern class NativePthreadCond in "C" `{ pthread_cond_t * `}
276 int r
= pthread_cond_init
(&cond
, NULL);
278 pthread_cond_t
*pcond
= malloc
(sizeof
(pthread_cond_t
));
279 memmove
(pcond
, &cond
, sizeof
(pthread_cond_t
));
285 fun destroy `{ pthread_cond_destroy(self); `}
287 fun signal
: Int `{ return pthread_cond_signal(self); `}
289 fun broadcast `{ pthread_cond_broadcast(self); `}
291 fun wait
(mutex
: NativePthreadMutex) `{ pthread_cond_wait(self, mutex); `}
297 # Cannot be extracted from this module because of the callback from C to `Thread::run
`
302 # Instances of this class are each used to launch and control a thread.
303 abstract class Thread
306 # Type returned by `main
`
307 type E : nullable Object
309 private var native: nullable NativePthread = null
311 # Is this thread finished ? True when main returned
314 # Main method of this thread
316 # The returned valued is passed to the caller of `join
`.
317 fun main: E do return null
319 private fun main_intern: E
321 # Register thread local data
322 sys.self_thread_key.set self
328 # Start executing this thread
330 # Will launch `main
` on a different thread.
333 if native != null then return
334 native = new NativePthread.create(self)
337 # Join this thread to the calling thread
339 # Blocks until the method `main
` returns or the target thread calls
340 # `Sys::thread_exit
`. Returns the object returned from the other thread.
342 # Stats the thread if now already done by a call to `start
`.
345 if native == null then start
353 if native == null then return
359 # The main thread of the program
366 # Exit current thread and return `value
` to caller of `Thread::join
`
367 fun exit_thread(value: nullable Object) `{ pthread_exit(value); `}
369 # Returns the handle to the running `Thread`
372 var key
= sys
.self_thread_key
375 # This is the original thread, get `Sys::main_thread` and store it
376 var thread
= sys
.main_thread
381 assert val
isa Thread
385 # Mutual exclusion synchronization tool
387 # Instances of this class can only be acquired by a single thread at any one
388 # point in time. Uses the recursive protocol so they can be locked many time by
389 # the same thread, must then be unlocked as many time.
393 private var native
: nullable NativePthreadMutex is noinit
397 var attr
= new NativePthreadMutexAttr
398 attr
.set_type_recursive
399 native
= new NativePthreadMutex(attr
)
404 # Acquire this lock, wait until it is available
405 fun lock
do native
.lock
407 # Acquire this lock only if it is available
409 # Returns `true` if the lock has been acquired.
410 fun try_lock
: Bool do return native
.try_lock
412 # Release this lock, unblocking all callers of `lock`
413 fun unlock
do native
.unlock
417 var native
= self.native
418 if native
!= null then
428 super FinalizableOnce
430 private var native
= new NativePthreadCond
433 redef fun finalize_once
do native
.destroy
435 # Signal at least one thread waiting to wake up
436 fun signal
: Int do return native
.signal
438 # Signal all the waiting threads to wake up
439 fun broadcast
do native
.broadcast
441 # Make the current thread waiting for a signal ( `mutex` should be locked)
442 fun wait
(mutex
: Mutex) do native
.wait
(mutex
.native
.as(not null))
445 # Barrier synchronization tool
447 # Ensures that `count` threads call and block on `wait` before releasing them.
451 private var mutex
= new Mutex
452 private var cond
: nullable NativePthreadCond = new NativePthreadCond
454 # Number of threads that must be waiting for `wait` to unblock
457 private var threads_waiting
= 0
459 # Wait at this barrier and block until there are a `count` threads waiting
464 if threads_waiting
== count
then
468 cond
.wait
(mutex
.native
.as(not null))
484 # Print `object` and '\n' with the same system call
485 redef fun print
(object
)
487 sys
.stdout
.write
(object
.to_s
+"\n")