src/doc: introduce option --no-render in HTML phase.
[nit.git] / lib / pthreads / pthreads.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Main POSIX threads support and intro the classes `Thread`, `Mutex` and `Barrier`
18 module pthreads is
19 cflags "-pthread"
20 ldflags "-pthread"
21 pkgconfig "bdw-gc"
22 new_annotation threaded
23 end
24
25 #
26 ## Native part
27 #
28 # Nity part at the bottom of the module.
29 #
30
31 in "C Header" `{
32 #include <pthread.h>
33 `}
34
35 in "C" `{
36 // TODO protect with: #ifdef WITH_LIBGC
37 // We might have to add the next line to gc_chooser.c too, especially
38 // if we get an error like "thread not registered with GC".
39 #ifndef ANDROID
40 #define GC_THREADS
41 #include <gc.h>
42 #endif
43 `}
44
45 redef class Sys
46
47 # `NativePthread` for running thread
48 private fun native_pthread_self: NativePthread `{
49 pthread_t *id = malloc(sizeof(pthread_t));
50 *id = pthread_self();
51 return id;
52 `}
53
54 private var self_thread_key = new NativePthreadKey
55
56 private var main_thread_cache: nullable MainThread = null
57 private var main_thread_mutex = new Mutex
58
59 # Handle to the program's main thread
60 fun main_thread: MainThread
61 do
62 var cache = main_thread_cache
63 if cache != null then return cache
64
65 main_thread_mutex.lock
66
67 # Recheck if cache has been updated since lock has been unlocked/locked
68 cache = main_thread_cache
69 if cache != null then
70 main_thread_mutex.unlock
71 return cache
72 end
73
74 # Create a `MainThread` exactly once
75 var thread = new MainThread
76 thread.native = sys.native_pthread_self
77 main_thread_cache = thread
78
79 main_thread_mutex.unlock
80 return thread
81 end
82 end
83
84 private extern class NativePthread in "C" `{ pthread_t * `}
85
86 new create(nit_thread: Thread) import Thread.main_intern `{
87 pthread_attr_t attr;
88 pthread_attr_init(&attr);
89
90 pthread_t thread;
91 int r = pthread_create(&thread, &attr, (void * (*)(void *))&Thread_main_intern, nit_thread);
92
93 if (r == 0) {
94 pthread_t *pthread = malloc(sizeof(pthread_t));
95 memmove(pthread, &thread, sizeof(pthread_t));
96 return pthread;
97 }
98 return NULL;
99 `}
100
101 new create_ex(nit_thread: Thread, attr: NativePthreadAttr) import Thread.main_intern `{
102 pthread_t thread;
103 int r = pthread_create(&thread, attr, (void * (*)(void *))&Thread_main_intern, nit_thread);
104
105 if (r == 0) {
106 pthread_t *pthread = malloc(sizeof(pthread_t));
107 memmove(pthread, &thread, sizeof(pthread_t));
108 return pthread;
109 }
110 return NULL;
111 `}
112
113 fun join: nullable Object `{
114 void *thread_return;
115 pthread_join(*self, &thread_return);
116 if(thread_return == NULL) thread_return = null_Object();
117 return (nullable_Object)thread_return;
118 `}
119
120 fun equal(other: NativePthread): Bool `{ return pthread_equal(*self, *other); `}
121
122 fun kill(signal: Int) `{ pthread_kill(*self, signal); `}
123 end
124
125 private extern class NativePthreadAttr in "C" `{ pthread_attr_t * `}
126 new `{
127 pthread_attr_t attr;
128 int r = pthread_attr_init(&attr);
129 if (r == 0) {
130 pthread_attr_t *pattr = malloc(sizeof(pthread_attr_t));
131 memmove(pattr, &attr, sizeof(pthread_attr_t));
132 return pattr;
133 }
134 return NULL;
135 `}
136
137 fun destroy `{
138 pthread_attr_destroy(self);
139 `}
140
141 # Most features of this class are still TODO
142 #
143 # * pthread_attr_setaffinity_np(3)
144 # * pthread_attr_setdetachstate
145 # * pthread_attr_setguardsize
146 # * pthread_attr_setinheritsched
147 # * pthread_attr_setschedparam
148 # * pthread_attr_setschedpolicy
149 # * pthread_attr_setscope
150 # * pthread_attr_setstack
151 # * pthread_attr_setstackaddr
152 # * pthread_attr_setstacksize
153 end
154
155 private extern class NativePthreadMutex in "C" `{ pthread_mutex_t * `}
156 new (attr: NativePthreadMutexAttr) `{
157 pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t));
158 int r = pthread_mutex_init(mutex, attr);
159 if (r != 0) {
160 free(mutex);
161 return NULL;
162 }
163 return mutex;
164 `}
165
166 fun destroy `{ pthread_mutex_destroy(self); `}
167
168 fun lock `{ pthread_mutex_lock(self); `}
169 fun try_lock: Bool `{ return pthread_mutex_trylock(self); `}
170 fun unlock `{ pthread_mutex_unlock(self); `}
171 end
172
173 private extern class NativePthreadMutexAttr in "C" `{ pthread_mutexattr_t * `}
174 new `{
175 pthread_mutexattr_t *attr = malloc(sizeof(pthread_mutexattr_t));
176 int r = pthread_mutexattr_init(attr);
177 if (r != 0) {
178 free(attr);
179 return NULL;
180 }
181 return attr;
182 `}
183
184 fun destroy `{ pthread_mutexattr_destroy(self); `}
185
186 fun set_type_normal `{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_NORMAL); `}
187 fun set_type_recursive `{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_RECURSIVE); `}
188 fun set_type_errorcheck `{ pthread_mutexattr_settype(self, PTHREAD_MUTEX_ERRORCHECK); `}
189
190 # pthread_mutexattr_setpshared
191 # pthread_mutexattr_setprotocol
192 # pthread_mutexattr_setproceiling
193 # pthread_mutexattr_setrobust_np
194 end
195
196 private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
197 new `{
198 pthread_key_t *key = malloc(sizeof(pthread_key_t));
199 int r = pthread_key_create(key, NULL);
200 if (r != 0) {
201 free(key);
202 return NULL;
203 }
204 return key;
205 `}
206
207 fun get: nullable Object `{
208 void *val = pthread_getspecific(*self);
209 if (val == NULL) val = null_Object();
210 return val;
211 `}
212
213 fun set(val: nullable Object) `{
214 pthread_setspecific(*self, val);
215 `}
216 end
217
218 private extern class NativePthreadCond in "C" `{ pthread_cond_t * `}
219 new `{
220 pthread_cond_t cond;
221 int r = pthread_cond_init(&cond, NULL);
222 if (r == 0) {
223 pthread_cond_t *pcond = malloc(sizeof(pthread_cond_t));
224 memmove(pcond, &cond, sizeof(pthread_cond_t));
225 return pcond;
226 }
227 return NULL;
228 `}
229
230 fun destroy `{ pthread_cond_destroy(self); `}
231
232 fun signal `{ pthread_cond_signal(self); `}
233
234 fun broadcast `{ pthread_cond_broadcast(self); `}
235
236 fun wait(mutex: NativePthreadMutex) `{ pthread_cond_wait(self, mutex); `}
237 end
238
239 #
240 ## Nity part
241 #
242 # Cannot be extracted from this module because of the callback from C to `Thread::run`
243 #
244
245 # Handle to a thread
246 #
247 # Instances of this class are each used to launch and control a thread.
248 abstract class Thread
249 super Finalizable
250
251 # Type returned by `main`
252 type E : nullable Object
253
254 private var native: nullable NativePthread = null
255
256 # Is this thread finished ? True when main returned
257 var is_done = false
258
259 # Main method of this thread
260 #
261 # The returned valued is passed to the caller of `join`.
262 fun main: E do return null
263
264 private fun main_intern: E
265 do
266 # Register thread local data
267 sys.self_thread_key.set self
268 var r = main
269 self.is_done = true
270 return r
271 end
272
273 # Start executing this thread
274 #
275 # Will launch `main` on a different thread.
276 fun start
277 do
278 if native != null then return
279 native = new NativePthread.create(self)
280 end
281
282 # Join this thread to the calling thread
283 #
284 # Blocks until the method `main` returns or the target thread calls
285 # `Sys::thread_exit`. Returns the object returned from the other thread.
286 #
287 # Stats the thread if now already done by a call to `start`.
288 fun join: E
289 do
290 if native == null then start
291 var r = native.join
292 native = null
293 return r.as(E)
294 end
295
296 redef fun finalize
297 do
298 if native == null then return
299 native.free
300 native = null
301 end
302 end
303
304 # The main thread of the program
305 class MainThread
306 super Thread
307
308 private init do end
309 end
310
311 # Exit current thread and return `value` to caller of `Thread::join`
312 fun exit_thread(value: nullable Object) `{ pthread_exit(value); `}
313
314 # Returns the handle to the running `Thread`
315 fun thread: Thread
316 do
317 var key = sys.self_thread_key
318 var val = key.get
319 if val == null then
320 # This is the original thread, get `Sys::main_thread` and store it
321 var thread = sys.main_thread
322 key.set thread
323 return thread
324 end
325
326 assert val isa Thread
327 return val
328 end
329
330 # Mutual exclusion synchronization tool
331 #
332 # Instances of this class can only be acquired by a single thread at any one
333 # point in time. Uses the recursive protocol so they can be locked many time by
334 # the same thread, must then be unlocked as many time.
335 class Mutex
336 super Finalizable
337
338 private var native: nullable NativePthreadMutex is noinit
339
340 init
341 do
342 var attr = new NativePthreadMutexAttr
343 attr.set_type_recursive
344 native = new NativePthreadMutex(attr)
345 attr.destroy
346 attr.free
347 end
348
349 # Acquire this lock, wait until it is available
350 fun lock do native.lock
351
352 # Acquire this lock only if it is available
353 #
354 # Returns `true` if the lock has been acquired.
355 fun try_lock: Bool do return native.try_lock
356
357 # Release this lock, unblocking all callers of `lock`
358 fun unlock do native.unlock
359
360 redef fun finalize
361 do
362 var native = self.native
363 if native != null then
364 native.destroy
365 native.free
366 end
367 self.native = null
368 end
369 end
370
371 # Barrier synchronization tool
372 #
373 # Ensures that `count` threads call and block on `wait` before releasing them.
374 class Barrier
375 super Finalizable
376
377 private var mutex = new Mutex
378 private var cond: nullable NativePthreadCond = new NativePthreadCond
379
380 # Number of threads that must be waiting for `wait` to unblock
381 var count: Int
382
383 private var threads_waiting = 0
384
385 # Wait at this barrier and block until there are a `count` threads waiting
386 fun wait
387 do
388 mutex.lock
389 threads_waiting += 1
390 if threads_waiting == count then
391 threads_waiting = 0
392 cond.broadcast
393 else
394 cond.wait(mutex.native.as(not null))
395 end
396 mutex.unlock
397 end
398
399 redef fun finalize
400 do
401 var cond = self.cond
402 if cond != null then
403 cond.destroy
404 cond.free
405 end
406 self.cond = null
407 end
408 end
409
410 # Print `object` and '\n' with the same system call
411 redef fun print(object)
412 do
413 sys.stdout.write(object.to_s+"\n")
414 end