Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 1728 lines (1525 sloc) 42.394 kB
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1 /*
2 * MacRuby implementation of Thread.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
5 *
9595725 update copyrights to 2011
Laurent Sansonetti authored
6 * Copyright (C) 2009-2011, Apple Inc. All rights reserved.
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
7 * Copyright (C) 2004-2007 Koichi Sasada
8 */
9
d0898dd include/ruby/macruby.h -> macruby_internal.h
Laurent Sansonetti authored
10 #include "macruby_internal.h"
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
11 #include "ruby/node.h"
12 #include "vm.h"
affdd1a when a thread exists prematurely because of an exception, write a mes…
Laurent Sansonetti authored
13 #include "objc.h"
9c1d230 committing experimental branch content
Laurent Sansonetti authored
14
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
15 VALUE rb_cThread;
16 VALUE rb_cThGroup;
17 VALUE rb_cMutex;
18
43ad84f some mutex work
Laurent Sansonetti authored
19 typedef struct rb_vm_mutex {
20 pthread_mutex_t mutex;
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
21 rb_vm_thread_t *thread;
43ad84f some mutex work
Laurent Sansonetti authored
22 } rb_vm_mutex_t;
23
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
24 #define GetMutexPtr(obj) ((rb_vm_mutex_t *)DATA_PTR(obj))
25
26 typedef struct {
27 bool enclosed;
28 VALUE threads;
29 VALUE mutex;
30 } rb_thread_group_t;
31
32 #define GetThreadGroupPtr(obj) ((rb_thread_group_t *)DATA_PTR(obj))
9c1d230 committing experimental branch content
Laurent Sansonetti authored
33
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
34 #if 0
9c1d230 committing experimental branch content
Laurent Sansonetti authored
35 static VALUE
36 thread_s_new(int argc, VALUE *argv, VALUE klass)
37 {
38 // TODO
39 return Qnil;
40 }
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
41 #endif
42
43 static VALUE
45e7828 fix a bug in {Thread,ThreadGroup,Mutex}#alloc where we would not retu…
Laurent Sansonetti authored
44 thread_s_alloc(VALUE self, SEL sel)
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
45 {
46 rb_vm_thread_t *t = (rb_vm_thread_t *)xmalloc(sizeof(rb_vm_thread_t));
7d822fe don't allow a Thread object to be initialized twice
Laurent Sansonetti authored
47 t->thread = 0;
c5fc3ae @Watson1978 initialize variable related to exception in Thread. fix #1460
Watson1978 authored
48 t->exception = Qnil;
45e7828 fix a bug in {Thread,ThreadGroup,Mutex}#alloc where we would not retu…
Laurent Sansonetti authored
49 return Data_Wrap_Struct(self, NULL, NULL, t);
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
50 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
51
affdd1a when a thread exists prematurely because of an exception, write a mes…
Laurent Sansonetti authored
52 static IMP
53 thread_finalize_imp_super = NULL;
54
55 static void
56 thread_finalize_imp(void *rcv, SEL sel)
57 {
58 rb_vm_thread_t *t = GetThreadPtr(rcv);
59 if (t->exception != Qnil && !t->joined_on_exception) {
60 fprintf(stderr, "*** Thread %p exited prematurely because of an uncaught exception:\n%s\n",
61 t->thread,
62 rb_str_cstr(rb_format_exception_message(t->exception)));
63 }
64 if (thread_finalize_imp_super != NULL) {
65 ((void(*)(void *, SEL))thread_finalize_imp_super)(rcv, sel);
66 }
67 }
68
9c1d230 committing experimental branch content
Laurent Sansonetti authored
69 static VALUE
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
70 thread_initialize(VALUE thread, SEL sel, int argc, const VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
71 {
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
72 if (!rb_block_given_p()) {
73 rb_raise(rb_eThreadError, "must be called with a block");
74 }
75 rb_vm_block_t *b = rb_vm_current_block();
76 assert(b != NULL);
77
78 rb_vm_thread_t *t = GetThreadPtr(thread);
7d822fe don't allow a Thread object to be initialized twice
Laurent Sansonetti authored
79 if (t->thread != 0) {
80 rb_raise(rb_eThreadError, "already initialized thread");
81 }
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
82 rb_vm_thread_pre_init(t, b, argc, argv, rb_vm_create_vm());
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
83
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
84 // The thread's group is always the parent's one.
d604765 don't always assume that a thread as a group
Laurent Sansonetti authored
85 // The parent group might be nil (ex. if created from GCD).
86 VALUE group = GetThreadPtr(rb_vm_current_thread())->group;
87 if (group != Qnil) {
88 rb_thgroup_add(group, thread);
89 }
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
90
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
91 // Retain the Thread object to avoid a potential GC, the corresponding
92 // release is done in rb_vm_thread_run().
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
93 GC_RETAIN(thread);
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
94
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
95 // Prepare attributes for the thread.
96 pthread_attr_t attr;
97 pthread_attr_init(&attr);
98 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
99 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
100 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
101
f073ffa pre-register new threads to the core earlier, to avoid race condition…
Laurent Sansonetti authored
102 // Register the thread to the core. We are doing this before actually
103 // running it because the current thread might perform a method poking at
104 // the current registered threads (such as Kernel#sleep) right after that.
105 rb_vm_register_thread(thread);
106
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
107 // Launch it.
108 if (pthread_create(&t->thread, &attr, (void *(*)(void *))rb_vm_thread_run,
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
109 (void *)thread) != 0) {
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
110 rb_sys_fail("pthread_create() failed");
111 }
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
112 pthread_attr_destroy(&attr);
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
113
114 return thread;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
115 }
116
f842fba implemented Thread.start/fork
Laurent Sansonetti authored
117 /*
118 * call-seq:
119 * Thread.start([args]*) {|args| block } => thread
120 * Thread.fork([args]*) {|args| block } => thread
121 *
122 * Basically the same as <code>Thread::new</code>. However, if class
123 * <code>Thread</code> is subclassed, then calling <code>start</code> in that
124 * subclass will not invoke the subclass's <code>initialize</code> method.
125 */
126
127 static VALUE
128 thread_start(VALUE klass, SEL sel, int argc, VALUE *argv)
129 {
130 VALUE th = thread_s_alloc(klass, 0);
131 return thread_initialize(th, 0, argc, argv);
132 }
133
9c1d230 committing experimental branch content
Laurent Sansonetti authored
134 VALUE
135 rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
136 {
137 // TODO
138 return Qnil;
139 }
140
141 /*
142 * call-seq:
143 * thr.join => thr
144 * thr.join(limit) => thr
145 *
146 * The calling thread will suspend execution and run <i>thr</i>. Does not
147 * return until <i>thr</i> exits or until <i>limit</i> seconds have passed. If
148 * the time limit expires, <code>nil</code> will be returned, otherwise
149 * <i>thr</i> is returned.
150 *
151 * Any threads not joined will be killed when the main program exits. If
152 * <i>thr</i> had previously raised an exception and the
153 * <code>abort_on_exception</code> and <code>$DEBUG</code> flags are not set
154 * (so the exception has not yet been processed) it will be processed at this
155 * time.
156 *
157 * a = Thread.new { print "a"; sleep(10); print "b"; print "c" }
158 * x = Thread.new { print "x"; Thread.pass; print "y"; print "z" }
159 * x.join # Let x thread finish, a will be killed on exit.
160 *
161 * <em>produces:</em>
162 *
163 * axyz
164 *
165 * The following example illustrates the <i>limit</i> parameter.
166 *
167 * y = Thread.new { 4.times { sleep 0.1; puts 'tick... ' }}
168 * puts "Waiting" until y.join(0.15)
169 *
170 * <em>produces:</em>
171 *
172 * tick...
173 * Waiting
174 * tick...
175 * Waitingtick...
176 *
177 *
178 * tick...
179 */
180
181 static VALUE
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
182 thread_join_m(VALUE self, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
183 {
459b19f more MT work
Laurent Sansonetti authored
184 VALUE timeout;
185
186 rb_scan_args(argc, argv, "01", &timeout);
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
187
188 rb_vm_thread_t *t = GetThreadPtr(self);
53b6204 more MT work
Laurent Sansonetti authored
189 if (t->status != THREAD_DEAD) {
190 if (timeout == Qnil) {
191 // No timeout given: block until the thread finishes.
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
192 //pthread_assert(pthread_join(t->thread, NULL));
193 struct timespec ts;
194 ts.tv_sec = 0;
195 ts.tv_nsec = 10000000;
196 while (t->status != THREAD_DEAD) {
197 nanosleep(&ts, NULL);
198 pthread_yield_np();
be9df8e @Watson1978 Thread#value should return nil when its thread was waited by Mutex#lo…
Watson1978 authored
199 if (t->status == THREAD_KILLED && t->wait_for_mutex_lock) {
200 goto dead;
201 }
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
202 }
459b19f more MT work
Laurent Sansonetti authored
203 }
53b6204 more MT work
Laurent Sansonetti authored
204 else {
54e99c4 Thread#join: when timeout is provided, make sure to do multiple sleep…
Laurent Sansonetti authored
205 // Timeout given: sleep and check if the thread is dead.
53b6204 more MT work
Laurent Sansonetti authored
206 struct timeval tv = rb_time_interval(timeout);
207 struct timespec ts;
208 ts.tv_sec = tv.tv_sec;
209 ts.tv_nsec = tv.tv_usec * 1000;
210 while (ts.tv_nsec >= 1000000000) {
211 ts.tv_sec += 1;
212 ts.tv_nsec -= 1000000000;
213 }
54e99c4 Thread#join: when timeout is provided, make sure to do multiple sleep…
Laurent Sansonetti authored
214
215 while (ts.tv_sec > 0 || ts.tv_nsec > 0) {
216 struct timespec its;
217 again:
218 if (ts.tv_nsec > 100000000) {
219 ts.tv_nsec -= 100000000;
220 its.tv_sec = 0;
221 its.tv_nsec = 100000000;
222 }
223 else if (ts.tv_sec > 0) {
224 ts.tv_sec -= 1;
225 ts.tv_nsec += 1000000000;
226 goto again;
227 }
228 else {
229 its = ts;
230 ts.tv_sec = ts.tv_nsec = 0;
231 }
232 nanosleep(&its, NULL);
233 if (t->status == THREAD_DEAD) {
234 goto dead;
235 }
be9df8e @Watson1978 Thread#value should return nil when its thread was waited by Mutex#lo…
Watson1978 authored
236 if (t->status == THREAD_KILLED && t->wait_for_mutex_lock) {
237 goto dead;
238 }
53b6204 more MT work
Laurent Sansonetti authored
239 }
54e99c4 Thread#join: when timeout is provided, make sure to do multiple sleep…
Laurent Sansonetti authored
240 return Qnil;
459b19f more MT work
Laurent Sansonetti authored
241 }
5e4754b don't try to join a dead thread
Laurent Sansonetti authored
242 }
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
243
54e99c4 Thread#join: when timeout is provided, make sure to do multiple sleep…
Laurent Sansonetti authored
244 dead:
53b6204 more MT work
Laurent Sansonetti authored
245 // If the thread was terminated because of an exception, we need to
246 // propagate it.
247 if (t->exception != Qnil) {
affdd1a when a thread exists prematurely because of an exception, write a mes…
Laurent Sansonetti authored
248 t->joined_on_exception = true;
53b6204 more MT work
Laurent Sansonetti authored
249 rb_exc_raise(t->exception);
250 }
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
251 return self;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
252 }
253
254 /*
255 * call-seq:
256 * thr.value => obj
257 *
258 * Waits for <i>thr</i> to complete (via <code>Thread#join</code>) and returns
259 * its value.
260 *
261 * a = Thread.new { 2 + 2 }
262 * a.value #=> 4
263 */
264
265 static VALUE
5113916 more MT work
Laurent Sansonetti authored
266 thread_value(VALUE self, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
267 {
5113916 more MT work
Laurent Sansonetti authored
268 thread_join_m(self, 0, 0, NULL);
269 return GetThreadPtr(self)->value;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
270 }
271
272 void
273 rb_thread_polling(void)
274 {
275 // TODO
276 }
277
278 void
279 rb_thread_schedule(void)
280 {
13a35ce @Watson1978 move pthread_yield_np() into rb_thread_schedule()
Watson1978 authored
281 pthread_yield_np();
9c1d230 committing experimental branch content
Laurent Sansonetti authored
282 }
283
284 int rb_thread_critical; /* TODO: dummy variable */
285
286 /*
287 * call-seq:
288 * Thread.pass => nil
289 *
290 * Invokes the thread scheduler to pass execution to another thread.
291 *
292 * a = Thread.new { print "a"; Thread.pass;
293 * print "b"; Thread.pass;
294 * print "c" }
295 * b = Thread.new { print "x"; Thread.pass;
296 * print "y"; Thread.pass;
297 * print "z" }
298 * a.join
299 * b.join
300 *
301 * <em>produces:</em>
302 *
303 * axbycz
304 */
305
306 static VALUE
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
307 thread_s_pass(VALUE klass, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
308 {
13a35ce @Watson1978 move pthread_yield_np() into rb_thread_schedule()
Watson1978 authored
309 rb_thread_schedule();
9c1d230 committing experimental branch content
Laurent Sansonetti authored
310 return Qnil;
311 }
312
313 /*
314 * call-seq:
315 * thr.raise(exception)
316 *
317 * Raises an exception (see <code>Kernel::raise</code>) from <i>thr</i>. The
318 * caller does not have to be <i>thr</i>.
319 *
320 * Thread.abort_on_exception = true
321 * a = Thread.new { sleep(200) }
322 * a.raise("Gotcha")
323 *
324 * <em>produces:</em>
325 *
326 * prog.rb:3: Gotcha (RuntimeError)
327 * from prog.rb:2:in `initialize'
328 * from prog.rb:2:in `new'
329 * from prog.rb:2
330 */
331
332 static VALUE
c0c6a6d Thread#raise: added
Laurent Sansonetti authored
333 thread_raise_m(VALUE self, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
334 {
c0c6a6d Thread#raise: added
Laurent Sansonetti authored
335 VALUE exc = rb_make_exception(argc, argv);
336
337 rb_vm_thread_t *t = GetThreadPtr(self);
338
339 if (t->thread == pthread_self()) {
340 rb_exc_raise(exc);
341 }
342 else if (t->status != THREAD_DEAD) {
343 rb_vm_thread_raise(t, exc);
344 }
345
9c1d230 committing experimental branch content
Laurent Sansonetti authored
346 return Qnil;
347 }
348
349 /*
350 * call-seq:
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
351 * thr.exit => thr
352 * thr.kill => thr
353 * thr.terminate => thr
9c1d230 committing experimental branch content
Laurent Sansonetti authored
354 *
355 * Terminates <i>thr</i> and schedules another thread to be run. If this thread
356 * is already marked to be killed, <code>exit</code> returns the
357 * <code>Thread</code>. If this is the main thread, or the last thread, exits
358 * the process.
359 */
360
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
361 static VALUE
362 rb_thread_kill(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
363 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
364 rb_vm_thread_t *t = GetThreadPtr(thread);
06296aa when killing the main thread, just exit the program (patch from watso…
Laurent Sansonetti authored
365 rb_vm_thread_t *t_main = GetThreadPtr(rb_vm_main_thread());
366 if (t->thread == t_main->thread) {
367 rb_exit(EXIT_SUCCESS);
368 }
8db1760 fixed the kill of a thread which is waiting for a cond var
Laurent Sansonetti authored
369 if (t->status != THREAD_KILLED) {
370 rb_vm_thread_cancel(t);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
371 }
372 return thread;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
373 }
374
375 /*
376 * call-seq:
377 * Thread.kill(thread) => thread
378 *
379 * Causes the given <em>thread</em> to exit (see <code>Thread::exit</code>).
380 *
381 * count = 0
382 * a = Thread.new { loop { count += 1 } }
383 * sleep(0.1) #=> 0
384 * Thread.kill(a) #=> #<Thread:0x401b3d30 dead>
385 * count #=> 93947
386 * a.alive? #=> false
387 */
388
389 static VALUE
8a1aab0 implement Thread.kill and Thread.exit
Laurent Sansonetti authored
390 rb_thread_s_kill(VALUE obj, SEL sel, VALUE th)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
391 {
d2cae1e fix a bug in Thread.kill when passing a non-Thread object would cause…
Laurent Sansonetti authored
392 if (!rb_obj_is_kind_of(th, rb_cThread)) {
393 rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)",
394 rb_obj_classname(th));
395 }
8a1aab0 implement Thread.kill and Thread.exit
Laurent Sansonetti authored
396 return rb_thread_kill(th, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
397 }
398
399 /*
400 * call-seq:
401 * Thread.exit => thread
402 *
403 * Terminates the currently running thread and schedules another thread to be
404 * run. If this thread is already marked to be killed, <code>exit</code>
405 * returns the <code>Thread</code>. If this is the main thread, or the last
406 * thread, exit the process.
407 */
408
409 static VALUE
410 rb_thread_exit(void)
411 {
8a1aab0 implement Thread.kill and Thread.exit
Laurent Sansonetti authored
412 return rb_thread_kill(rb_vm_current_thread(), 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
413 }
414
415 /*
416 * call-seq:
417 * thr.wakeup => thr
418 *
419 * Marks <i>thr</i> as eligible for scheduling (it may still remain blocked on
420 * I/O, however). Does not invoke the scheduler (see <code>Thread#run</code>).
421 *
422 * c = Thread.new { Thread.stop; puts "hey!" }
423 * c.wakeup
424 *
425 * <em>produces:</em>
426 *
427 * hey!
428 */
429
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
430 static VALUE
431 rb_thread_wakeup(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
432 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
433 rb_vm_thread_wakeup(GetThreadPtr(thread));
872df62 more MT compliance
Laurent Sansonetti authored
434 return thread;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
435 }
436
437 /*
438 * call-seq:
439 * thr.run => thr
440 *
441 * Wakes up <i>thr</i>, making it eligible for scheduling.
442 *
443 * a = Thread.new { puts "a"; Thread.stop; puts "c" }
444 * Thread.pass
445 * puts "Got here"
446 * a.run
447 * a.join
448 *
449 * <em>produces:</em>
450 *
451 * a
452 * Got here
453 * c
454 */
455
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
456 static VALUE
457 rb_thread_run(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
458 {
872df62 more MT compliance
Laurent Sansonetti authored
459 rb_vm_thread_wakeup(GetThreadPtr(thread));
460 pthread_yield_np();
461 return thread;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
462 }
463
464 /*
465 * call-seq:
466 * Thread.stop => nil
467 *
468 * Stops execution of the current thread, putting it into a ``sleep'' state,
469 * and schedules execution of another thread.
470 *
471 * a = Thread.new { print "a"; Thread.stop; print "c" }
472 * Thread.pass
473 * print "b"
474 * a.run
475 * a.join
476 *
477 * <em>produces:</em>
478 *
479 * abc
480 */
481
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
482 static VALUE
483 rb_thread_stop(VALUE rcv, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
484 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
485 rb_thread_sleep_forever();
9c1d230 committing experimental branch content
Laurent Sansonetti authored
486 return Qnil;
487 }
488
489 /*
490 * call-seq:
491 * Thread.list => array
492 *
493 * Returns an array of <code>Thread</code> objects for all threads that are
494 * either runnable or stopped.
495 *
496 * Thread.new { sleep(200) }
497 * Thread.new { 1000000.times {|i| i*i } }
498 * Thread.new { Thread.stop }
499 * Thread.list.each {|t| p t}
500 *
501 * <em>produces:</em>
502 *
503 * #<Thread:0x401b3e84 sleep>
504 * #<Thread:0x401b3f38 run>
505 * #<Thread:0x401b3fb0 sleep>
506 * #<Thread:0x401bdf4c run>
507 */
508
509 VALUE
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
510 rb_thread_list(VALUE rcv, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
511 {
b0831d8 Thread.list: do not return the internal thread list but a copy instead
Laurent Sansonetti authored
512 return rb_ary_dup(rb_vm_threads());
9c1d230 committing experimental branch content
Laurent Sansonetti authored
513 }
514
515 /*
516 * call-seq:
517 * Thread.current => thread
518 *
519 * Returns the currently executing thread.
520 *
521 * Thread.current #=> #<Thread:0x401bdf4c run>
522 */
523
524 static VALUE
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
525 thread_s_current(VALUE klass, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
526 {
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
527 return rb_vm_current_thread();
9c1d230 committing experimental branch content
Laurent Sansonetti authored
528 }
529
530 static VALUE
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
531 rb_thread_s_main(VALUE klass, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
532 {
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
533 return rb_vm_main_thread();
9c1d230 committing experimental branch content
Laurent Sansonetti authored
534 }
535
536 /*
537 * call-seq:
538 * Thread.abort_on_exception => true or false
539 *
540 * Returns the status of the global ``abort on exception'' condition. The
541 * default is <code>false</code>. When set to <code>true</code>, or if the
542 * global <code>$DEBUG</code> flag is <code>true</code> (perhaps because the
543 * command line option <code>-d</code> was specified) all threads will abort
544 * (the process will <code>exit(0)</code>) if an exception is raised in any
545 * thread. See also <code>Thread::abort_on_exception=</code>.
546 */
547
548 static VALUE
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
549 rb_thread_s_abort_exc(VALUE rcv, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
550 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
551 return rb_vm_abort_on_exception() ? Qtrue : Qfalse;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
552 }
553
554 /*
555 * call-seq:
556 * Thread.abort_on_exception= boolean => true or false
557 *
558 * When set to <code>true</code>, all threads will abort if an exception is
559 * raised. Returns the new state.
560 *
561 * Thread.abort_on_exception = true
562 * t1 = Thread.new do
563 * puts "In new thread"
564 * raise "Exception from thread"
565 * end
566 * sleep(1)
567 * puts "not reached"
568 *
569 * <em>produces:</em>
570 *
571 * In new thread
572 * prog.rb:4: Exception from thread (RuntimeError)
573 * from prog.rb:2:in `initialize'
574 * from prog.rb:2:in `new'
575 * from prog.rb:2
576 */
577
578 static VALUE
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
579 rb_thread_s_abort_exc_set(VALUE self, SEL sel, VALUE val)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
580 {
2982681 @Watson1978 Thread.abort_on_exception= should raise SecurityError when $SAFE is 4
Watson1978 authored
581 rb_secure(4);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
582 rb_vm_set_abort_on_exception(RTEST(val));
583 return val;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
584 }
585
586 /*
587 * call-seq:
588 * thr.abort_on_exception => true or false
589 *
590 * Returns the status of the thread-local ``abort on exception'' condition for
591 * <i>thr</i>. The default is <code>false</code>. See also
592 * <code>Thread::abort_on_exception=</code>.
593 */
594
595 static VALUE
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
596 rb_thread_abort_exc(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
597 {
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
598 return GetThreadPtr(thread)->abort_on_exception ? Qtrue : Qfalse;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
599 }
600
601 /*
602 * call-seq:
603 * thr.abort_on_exception= boolean => true or false
604 *
605 * When set to <code>true</code>, causes all threads (including the main
606 * program) to abort if an exception is raised in <i>thr</i>. The process will
607 * effectively <code>exit(0)</code>.
608 */
609
610 static VALUE
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
611 rb_thread_abort_exc_set(VALUE thread, SEL sel, VALUE val)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
612 {
2982681 @Watson1978 Thread.abort_on_exception= should raise SecurityError when $SAFE is 4
Watson1978 authored
613 rb_secure(4);
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
614 GetThreadPtr(thread)->abort_on_exception = RTEST(val);
615 return val;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
616 }
617
618 /*
619 * call-seq:
620 * thr.group => thgrp or nil
621 *
622 * Returns the <code>ThreadGroup</code> which contains <i>thr</i>, or nil if
623 * the thread is not a member of any group.
624 *
625 * Thread.main.group #=> #<ThreadGroup:0x4029d914>
626 */
627
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
628 static VALUE
629 rb_thread_group(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
630 {
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
631 return GetThreadPtr(thread)->group;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
632 }
633
634 /*
635 * call-seq:
636 * thr.status => string, false or nil
637 *
638 * Returns the status of <i>thr</i>: ``<code>sleep</code>'' if <i>thr</i> is
639 * sleeping or waiting on I/O, ``<code>run</code>'' if <i>thr</i> is executing,
640 * ``<code>aborting</code>'' if <i>thr</i> is aborting, <code>false</code> if
641 * <i>thr</i> terminated normally, and <code>nil</code> if <i>thr</i>
642 * terminated with an exception.
643 *
644 * a = Thread.new { raise("die now") }
645 * b = Thread.new { Thread.stop }
646 * c = Thread.new { Thread.exit }
647 * d = Thread.new { sleep }
648 * d.kill #=> #<Thread:0x401b3678 aborting>
649 * a.status #=> nil
650 * b.status #=> "sleep"
651 * c.status #=> false
652 * d.status #=> "aborting"
653 * Thread.current.status #=> "run"
654 */
655
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
656 static const char *
657 rb_thread_status_cstr(VALUE thread)
658 {
659 rb_vm_thread_t *t = GetThreadPtr(thread);
660 switch (t->status) {
661 case THREAD_ALIVE:
662 return "run";
663
664 case THREAD_SLEEP:
665 return "sleep";
666
667 case THREAD_KILLED:
8d28997 more MT work
Laurent Sansonetti authored
668 return "aborting";
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
669
670 case THREAD_DEAD:
671 return "dead";
672 }
673 return "unknown";
674 }
675
9c1d230 committing experimental branch content
Laurent Sansonetti authored
676 static VALUE
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
677 rb_thread_status(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
678 {
459b19f more MT work
Laurent Sansonetti authored
679 rb_vm_thread_t *t = GetThreadPtr(thread);
680 if (t->status == THREAD_DEAD) {
53b6204 more MT work
Laurent Sansonetti authored
681 return t->exception == Qnil ? Qfalse : Qnil;
459b19f more MT work
Laurent Sansonetti authored
682 }
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
683 return rb_str_new2(rb_thread_status_cstr(thread));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
684 }
685
686 /*
687 * call-seq:
688 * thr.alive? => true or false
689 *
690 * Returns <code>true</code> if <i>thr</i> is running or sleeping.
691 *
692 * thr = Thread.new { }
693 * thr.join #=> #<Thread:0x401b3fb0 dead>
694 * Thread.current.alive? #=> true
695 * thr.alive? #=> false
696 */
697
698 static VALUE
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
699 rb_thread_alive_p(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
700 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
701 rb_vm_thread_status_t s = GetThreadPtr(thread)->status;
8d28997 more MT work
Laurent Sansonetti authored
702 return s != THREAD_DEAD ? Qtrue : Qfalse;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
703 }
704
705 /*
706 * call-seq:
707 * thr.stop? => true or false
708 *
709 * Returns <code>true</code> if <i>thr</i> is dead or sleeping.
710 *
711 * a = Thread.new { Thread.stop }
712 * b = Thread.current
713 * a.stop? #=> true
714 * b.stop? #=> false
715 */
716
717 static VALUE
718 rb_thread_stop_p(VALUE thread)
719 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
720 rb_vm_thread_status_t s = GetThreadPtr(thread)->status;
721 return s == THREAD_DEAD || s == THREAD_SLEEP ? Qtrue : Qfalse;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
722 }
723
724 /*
725 * call-seq:
726 * thr.safe_level => integer
727 *
728 * Returns the safe level in effect for <i>thr</i>. Setting thread-local safe
729 * levels can help when implementing sandboxes which run insecure code.
730 *
731 * thr = Thread.new { $SAFE = 3; sleep }
732 * Thread.current.safe_level #=> 0
733 * thr.safe_level #=> 3
734 */
735
736 static VALUE
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
737 rb_thread_safe_level(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
738 {
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
739 return INT2FIX(rb_vm_thread_safe_level(GetThreadPtr(thread)));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
740 }
741
742 /*
743 * call-seq:
744 * thr.inspect => string
745 *
746 * Dump the name, id, and status of _thr_ to a string.
747 */
748
749 static VALUE
5113916 more MT work
Laurent Sansonetti authored
750 rb_thread_inspect(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
751 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
752 const char *status = rb_thread_status_cstr(thread);
5113916 more MT work
Laurent Sansonetti authored
753
754 char buf[100];
755 snprintf(buf, sizeof buf, "#<%s:%p %s>", rb_obj_classname(thread),
756 (void *)thread, status);
757
bbf842b @Watson1978 Thread#inspect will return string which copied receiver's status of t…
Watson1978 authored
758 VALUE str = rb_str_new2(buf);
759 OBJ_INFECT(str, thread);
760
761 return str;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
762 }
763
764 /*
765 * call-seq:
766 * thr[sym] => obj or nil
767 *
768 * Attribute Reference---Returns the value of a thread-local variable, using
769 * either a symbol or a string name. If the specified variable does not exist,
770 * returns <code>nil</code>.
771 *
772 * a = Thread.new { Thread.current["name"] = "A"; Thread.stop }
773 * b = Thread.new { Thread.current[:name] = "B"; Thread.stop }
774 * c = Thread.new { Thread.current["name"] = "C"; Thread.stop }
775 * Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" }
776 *
777 * <em>produces:</em>
778 *
779 * #<Thread:0x401b3b3c sleep>: C
780 * #<Thread:0x401b3bc8 sleep>: B
781 * #<Thread:0x401b3c68 sleep>: A
782 * #<Thread:0x401bdf4c run>:
783 */
784
785 static VALUE
84c7e85 implemented thread locals
Laurent Sansonetti authored
786 rb_thread_aref(VALUE thread, SEL sel, VALUE key)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
787 {
84c7e85 implemented thread locals
Laurent Sansonetti authored
788 key = ID2SYM(rb_to_id(key));
789 VALUE h = rb_vm_thread_locals(thread, false);
790 if (h != Qnil) {
791 return rb_hash_aref(h, key);
792 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
793 return Qnil;
794 }
795
f4f6988 implement missing MRI API: rb_thread_local_aref/aset
Laurent Sansonetti authored
796 VALUE
797 rb_thread_local_aref(VALUE self, ID key)
798 {
799 return rb_thread_aref(self, 0, ID2SYM(key));
800 }
801
9c1d230 committing experimental branch content
Laurent Sansonetti authored
802 /*
803 * call-seq:
804 * thr[sym] = obj => obj
805 *
806 * Attribute Assignment---Sets or creates the value of a thread-local variable,
807 * using either a symbol or a string. See also <code>Thread#[]</code>.
808 */
809
810 static VALUE
f4f6988 implement missing MRI API: rb_thread_local_aref/aset
Laurent Sansonetti authored
811 rb_thread_aset(VALUE self, SEL sel, VALUE key, VALUE val)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
812 {
84c7e85 implemented thread locals
Laurent Sansonetti authored
813 key = ID2SYM(rb_to_id(key));
814 return rb_hash_aset(rb_vm_thread_locals(self, true), key, val);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
815 }
816
f4f6988 implement missing MRI API: rb_thread_local_aref/aset
Laurent Sansonetti authored
817 VALUE
818 rb_thread_local_aset(VALUE self, ID key, VALUE val)
819 {
820 return rb_thread_aset(self, 0, ID2SYM(key), val);
821 }
822
9c1d230 committing experimental branch content
Laurent Sansonetti authored
823 /*
824 * call-seq:
825 * thr.key?(sym) => true or false
826 *
827 * Returns <code>true</code> if the given string (or symbol) exists as a
828 * thread-local variable.
829 *
830 * me = Thread.current
831 * me[:oliver] = "a"
832 * me.key?(:oliver) #=> true
833 * me.key?(:stanley) #=> false
834 */
835
836 static VALUE
84c7e85 implemented thread locals
Laurent Sansonetti authored
837 rb_thread_key_p(VALUE self, SEL sel, VALUE key)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
838 {
84c7e85 implemented thread locals
Laurent Sansonetti authored
839 key = ID2SYM(rb_to_id(key));
840 VALUE h = rb_vm_thread_locals(self, false);
841 if (h == Qnil) {
842 return Qfalse;
843 }
844 return rb_hash_has_key(h, key);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
845 }
846
847 int
848 rb_thread_alone()
849 {
1b9671b raise an exception in case we try to stop the only running thread (pa…
Laurent Sansonetti authored
850 return RARRAY_LEN(rb_vm_threads()) <= 1;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
851 }
852
853 /*
854 * call-seq:
855 * thr.keys => array
856 *
857 * Returns an an array of the names of the thread-local variables (as Symbols).
858 *
859 * thr = Thread.new do
860 * Thread.current[:cat] = 'meow'
861 * Thread.current["dog"] = 'woof'
862 * end
863 * thr.join #=> #<Thread:0x401b3f10 dead>
864 * thr.keys #=> [:dog, :cat]
865 */
866
867 static VALUE
84c7e85 implemented thread locals
Laurent Sansonetti authored
868 rb_thread_keys(VALUE self, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
869 {
84c7e85 implemented thread locals
Laurent Sansonetti authored
870 VALUE h = rb_vm_thread_locals(self, false);
871 return h == Qnil ? rb_ary_new() : rb_hash_keys(h);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
872 }
873
874 /*
875 * call-seq:
876 * thr.priority => integer
877 *
878 * Returns the priority of <i>thr</i>. Default is inherited from the
879 * current thread which creating the new thread, or zero for the
880 * initial main thread; higher-priority threads will run before
881 * lower-priority threads.
882 *
883 * Thread.current.priority #=> 0
884 */
885
886 static VALUE
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
887 rb_thread_priority(VALUE thread, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
888 {
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
889 // FIXME this doesn't really minic what 1.9 does, but do we care?
890 struct sched_param param;
891 pthread_assert(pthread_getschedparam(GetThreadPtr(thread)->thread,
892 NULL, &param));
893 return INT2FIX(param.sched_priority);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
894 }
895
896 /*
897 * call-seq:
898 * thr.priority= integer => thr
899 *
900 * Sets the priority of <i>thr</i> to <i>integer</i>. Higher-priority threads
901 * will run before lower-priority threads.
902 *
903 * count1 = count2 = 0
904 * a = Thread.new do
905 * loop { count1 += 1 }
906 * end
907 * a.priority = -1
908 *
909 * b = Thread.new do
910 * loop { count2 += 1 }
911 * end
912 * b.priority = -2
913 * sleep 1 #=> 1
914 * count1 #=> 622504
915 * count2 #=> 5832
916 */
917
918 static VALUE
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
919 rb_thread_priority_set(VALUE thread, SEL sel, VALUE prio)
920 {
921 // FIXME this doesn't really minic what 1.9 does, but do we care?
922 int policy;
923 struct sched_param param;
e767a91 @Watson1978 Thread#priority= should raise SecurityError when $SAFE is 4
Watson1978 authored
924 rb_secure(4);
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
925 pthread_assert(pthread_getschedparam(GetThreadPtr(thread)->thread,
926 &policy, &param));
e767a91 @Watson1978 Thread#priority= should raise SecurityError when $SAFE is 4
Watson1978 authored
927
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
928 const int max = sched_get_priority_max(policy);
929 const int min = sched_get_priority_min(policy);
930
931 int priority = FIX2INT(prio);
932 if (min > priority) {
933 priority = min;
934 }
935 else if (max > priority) {
936 priority = max;
937 }
938
939 param.sched_priority = priority;
940 pthread_assert(pthread_setschedparam(GetThreadPtr(thread)->thread,
941 policy, &param));
942
9c1d230 committing experimental branch content
Laurent Sansonetti authored
943 return Qnil;
944 }
945
946 /* for IO */
947 // TODO these should be moved into io.c
948
949 #if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
950 void
951 rb_fd_init(volatile rb_fdset_t *fds)
952 {
953 fds->maxfd = 0;
954 GC_WB(&fds->fdset, ALLOC(fd_set));
955 FD_ZERO(fds->fdset);
956 }
957
958 void
959 rb_fd_term(rb_fdset_t *fds)
960 {
bd801b0 fix potential memory problems in select() code
Laurent Sansonetti authored
961 if (fds->fdset != NULL) {
962 xfree(fds->fdset);
963 fds->fdset = NULL;
964 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
965 fds->maxfd = 0;
966 fds->fdset = 0;
967 }
968
969 void
970 rb_fd_zero(rb_fdset_t *fds)
971 {
972 if (fds->fdset) {
973 MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
974 FD_ZERO(fds->fdset);
975 }
976 }
977
978 static void
979 rb_fd_resize(int n, rb_fdset_t *fds)
980 {
981 int m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
982 int o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
983
984 if (m < sizeof(fd_set)) m = sizeof(fd_set);
985 if (o < sizeof(fd_set)) o = sizeof(fd_set);
986
987 if (m > o) {
988 GC_WB(&fds->fdset, xrealloc(fds->fdset, m));
989 memset((char *)fds->fdset + o, 0, m - o);
990 }
991 if (n >= fds->maxfd) fds->maxfd = n + 1;
992 }
993
994 void
995 rb_fd_set(int n, rb_fdset_t *fds)
996 {
997 rb_fd_resize(n, fds);
998 FD_SET(n, fds->fdset);
999 }
1000
1001 void
1002 rb_fd_clr(int n, rb_fdset_t *fds)
1003 {
1004 if (n >= fds->maxfd) return;
1005 FD_CLR(n, fds->fdset);
1006 }
1007
1008 int
1009 rb_fd_isset(int n, const rb_fdset_t *fds)
1010 {
1011 if (n >= fds->maxfd) return 0;
1012 return FD_ISSET(n, fds->fdset) != 0; /* "!= 0" avoids FreeBSD PR 91421 */
1013 }
1014
1015 void
1016 rb_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
1017 {
1018 int size = howmany(max, NFDBITS) * sizeof(fd_mask);
1019
1020 if (size < sizeof(fd_set)) size = sizeof(fd_set);
1021 dst->maxfd = max;
1022 GC_WB(&dst->fdset, xrealloc(dst->fdset, size));
1023 memcpy(dst->fdset, src, size);
1024 }
1025
1026 int
1027 rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout)
1028 {
1029 fd_set *r = NULL, *w = NULL, *e = NULL;
1030 if (readfds) {
1031 rb_fd_resize(n - 1, readfds);
1032 r = rb_fd_ptr(readfds);
1033 }
1034 if (writefds) {
1035 rb_fd_resize(n - 1, writefds);
1036 w = rb_fd_ptr(writefds);
1037 }
1038 if (exceptfds) {
1039 rb_fd_resize(n - 1, exceptfds);
1040 e = rb_fd_ptr(exceptfds);
1041 }
1042 return select(n, r, w, e, timeout);
1043 }
1044
1045 #undef FD_ZERO
1046 #undef FD_SET
1047 #undef FD_CLR
1048 #undef FD_ISSET
1049
1050 #define FD_ZERO(f) rb_fd_zero(f)
1051 #define FD_SET(i, f) rb_fd_set(i, f)
1052 #define FD_CLR(i, f) rb_fd_clr(i, f)
1053 #define FD_ISSET(i, f) rb_fd_isset(i, f)
1054
1055 #endif
1056
1057 static double
1058 timeofday(void)
1059 {
1060 struct timeval tv;
1061 gettimeofday(&tv, NULL);
1062 return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
1063 }
1064
1065 static int
1066 do_select(int n, fd_set *read, fd_set *write, fd_set *except,
1067 struct timeval *timeout)
1068 {
1069 int result, lerrno;
1070 fd_set orig_read, orig_write, orig_except;
1071
1072 bzero(&orig_read, sizeof(fd_set));
1073 bzero(&orig_write, sizeof(fd_set));
1074 bzero(&orig_except, sizeof(fd_set));
1075
1076 #ifndef linux
1077 double limit = 0;
1078 struct timeval wait_rest;
1079
1080 if (timeout) {
1081 limit = timeofday() +
1082 (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
1083 wait_rest = *timeout;
1084 timeout = &wait_rest;
1085 }
1086 #endif
1087
1088 if (read) orig_read = *read;
1089 if (write) orig_write = *write;
1090 if (except) orig_except = *except;
1091
1092 retry:
1093 lerrno = 0;
1094
fff9e91 @Watson1978 change thread's status during blocking with select. fix #1425
Watson1978 authored
1095 rb_vm_thread_t *thread = GetThreadPtr(rb_vm_current_thread());
1096 rb_vm_thread_status_t prev_status = thread->status;
1097 thread->status = THREAD_SLEEP;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1098 //BLOCKING_REGION({
1099 result = select(n, read, write, except, timeout);
1100 if (result < 0) lerrno = errno;
1101 //}, ubf_select, GET_THREAD());
fff9e91 @Watson1978 change thread's status during blocking with select. fix #1425
Watson1978 authored
1102 thread->status = prev_status;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1103
1104 errno = lerrno;
1105
1106 if (result < 0) {
1107 switch (errno) {
1108 case EINTR:
1109 #ifdef ERESTART
1110 case ERESTART:
1111 #endif
1112 if (read) *read = orig_read;
1113 if (write) *write = orig_write;
1114 if (except) *except = orig_except;
1115 #ifndef linux
1116 if (timeout) {
1117 double d = limit - timeofday();
1118
1119 wait_rest.tv_sec = (unsigned int)d;
1120 wait_rest.tv_usec = (long)((d-(double)wait_rest.tv_sec)*1e6);
1121 if (wait_rest.tv_sec < 0) wait_rest.tv_sec = 0;
1122 if (wait_rest.tv_usec < 0) wait_rest.tv_usec = 0;
1123 }
1124 #endif
1125 goto retry;
1126 default:
1127 break;
1128 }
1129 }
1130 return result;
1131 }
1132
1133 static void
1134 rb_thread_wait_fd_rw(int fd, int read)
1135 {
1136 int result = 0;
1137
1138 while (result <= 0) {
1139 rb_fdset_t *set = ALLOC(rb_fdset_t);
1140 rb_fd_init(set);
1141 FD_SET(fd, set);
1142
1143 if (read) {
1144 result = do_select(fd + 1, rb_fd_ptr(set), 0, 0, 0);
1145 }
1146 else {
1147 result = do_select(fd + 1, 0, rb_fd_ptr(set), 0, 0);
1148 }
1149
1150 rb_fd_term(set);
1151
1152 if (result < 0) {
1153 rb_sys_fail(0);
1154 }
1155 }
1156 }
1157
1158 void
1159 rb_thread_wait_fd(int fd)
1160 {
1161 rb_thread_wait_fd_rw(fd, 1);
1162 }
1163
1164 int
1165 rb_thread_fd_writable(int fd)
1166 {
1167 rb_thread_wait_fd_rw(fd, 0);
1168 return Qtrue;
1169 }
1170
1171 int
1172 rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except,
1173 struct timeval *timeout)
1174 {
1175 if (!read && !write && !except) {
1176 if (!timeout) {
1177 rb_thread_sleep_forever();
1178 return 0;
1179 }
1180 rb_thread_wait_for(*timeout);
1181 return 0;
1182 }
1183 else {
1184 return do_select(max, read, write, except, timeout);
1185 }
1186 }
1187
1188 /*
1189 * Document-class: ThreadGroup
1190 *
1191 * <code>ThreadGroup</code> provides a means of keeping track of a number of
1192 * threads as a group. A <code>Thread</code> can belong to only one
1193 * <code>ThreadGroup</code> at a time; adding a thread to a new group will
1194 * remove it from any previous group.
1195 *
1196 * Newly created threads belong to the same group as the thread from which they
1197 * were created.
1198 */
1199
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1200 static VALUE mutex_s_alloc(VALUE self, SEL sel);
1201 static VALUE mutex_initialize(VALUE self, SEL sel);
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1202
1203 static VALUE
1204 thgroup_s_alloc(VALUE self, SEL sel)
1205 {
1206 rb_thread_group_t *t = (rb_thread_group_t *)xmalloc(
1207 sizeof(rb_thread_group_t));
1208 t->enclosed = false;
1209 GC_WB(&t->threads, rb_ary_new());
34d1835 fix a bug in Mutex and ThreadGroup where modifying internal array str…
Laurent Sansonetti authored
1210 OBJ_UNTRUST(t->threads);
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1211
1212 VALUE mutex = mutex_s_alloc(rb_cMutex, 0);
1213 mutex_initialize(mutex, 0);
1214 GC_WB(&t->mutex, mutex);
1215
45e7828 fix a bug in {Thread,ThreadGroup,Mutex}#alloc where we would not retu…
Laurent Sansonetti authored
1216 return Data_Wrap_Struct(self, NULL, NULL, t);
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1217 }
1218
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1219 /*
1220 * call-seq:
1221 * thgrp.list => array
1222 *
1223 * Returns an array of all existing <code>Thread</code> objects that belong to
1224 * this group.
1225 *
1226 * ThreadGroup::Default.list #=> [#<Thread:0x401bdf4c run>]
1227 */
1228
1229 static VALUE
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1230 thgroup_list(VALUE group, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1231 {
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1232 return GetThreadGroupPtr(group)->threads;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1233 }
1234
1235 /*
1236 * call-seq:
1237 * thgrp.enclose => thgrp
1238 *
1239 * Prevents threads from being added to or removed from the receiving
1240 * <code>ThreadGroup</code>. New threads can still be started in an enclosed
1241 * <code>ThreadGroup</code>.
1242 *
1243 * ThreadGroup::Default.enclose #=> #<ThreadGroup:0x4029d914>
1244 * thr = Thread::new { Thread.stop } #=> #<Thread:0x402a7210 sleep>
1245 * tg = ThreadGroup::new #=> #<ThreadGroup:0x402752d4>
1246 * tg.add thr
1247 *
1248 * <em>produces:</em>
1249 *
1250 * ThreadError: can't move from the enclosed thread group
1251 */
1252
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1253 static VALUE
1254 thgroup_enclose(VALUE group, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1255 {
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1256 GetThreadGroupPtr(group)->enclosed = true;
1257 return group;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1258 }
1259
1260 /*
1261 * call-seq:
1262 * thgrp.enclosed? => true or false
1263 *
1264 * Returns <code>true</code> if <em>thgrp</em> is enclosed. See also
1265 * ThreadGroup#enclose.
1266 */
1267
1268 static VALUE
1269 thgroup_enclosed_p(VALUE group)
1270 {
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1271 return GetThreadGroupPtr(group)->enclosed ? Qtrue : Qfalse;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1272 }
1273
1274 /*
1275 * call-seq:
1276 * thgrp.add(thread) => thgrp
1277 *
1278 * Adds the given <em>thread</em> to this group, removing it from any other
1279 * group to which it may have previously belonged.
1280 *
1281 * puts "Initial group is #{ThreadGroup::Default.list}"
1282 * tg = ThreadGroup.new
1283 * t1 = Thread.new { sleep }
1284 * t2 = Thread.new { sleep }
1285 * puts "t1 is #{t1}"
1286 * puts "t2 is #{t2}"
1287 * tg.add(t1)
1288 * puts "Initial group now #{ThreadGroup::Default.list}"
1289 * puts "tg group now #{tg.list}"
1290 *
1291 * <em>produces:</em>
1292 *
1293 * Initial group is #<Thread:0x401bdf4c>
1294 * t1 is #<Thread:0x401b3c90>
1295 * t2 is #<Thread:0x401b3c18>
1296 * Initial group now #<Thread:0x401b3c18>#<Thread:0x401bdf4c>
1297 * tg group now #<Thread:0x401b3c90>
1298 */
1299
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1300 static inline void
1301 thgroup_lock(rb_thread_group_t *tg)
1302 {
1303 pthread_assert(pthread_mutex_lock(&GetMutexPtr(tg->mutex)->mutex));
1304 }
1305
1306 static inline void
1307 thgroup_unlock(rb_thread_group_t *tg)
1308 {
1309 pthread_assert(pthread_mutex_unlock(&GetMutexPtr(tg->mutex)->mutex));
1310 }
1311
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1312 static VALUE
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1313 thgroup_add(VALUE group, SEL sel, VALUE thread)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1314 {
72597f4 honor ThreadGroup frozen state
Laurent Sansonetti authored
1315 if (OBJ_FROZEN(group)) {
1316 rb_raise(rb_eThreadError, "can't move to the frozen thread group");
1317 }
1318
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1319 rb_vm_thread_t *t = GetThreadPtr(thread);
1320
1321 rb_thread_group_t *new_tg = GetThreadGroupPtr(group);
1322 if (new_tg->enclosed) {
1323 rb_raise(rb_eThreadError, "can't move from the enclosed thread group");
1324 }
1325
1326 if (t->group != Qnil) {
72597f4 honor ThreadGroup frozen state
Laurent Sansonetti authored
1327 if (OBJ_FROZEN(t->group)) {
1328 rb_raise(rb_eThreadError,
1329 "can't move from the frozen thread group");
1330 }
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1331 rb_thread_group_t *old_tg = GetThreadGroupPtr(t->group);
1332 if (old_tg->enclosed) {
1333 rb_raise(rb_eThreadError,
1334 "can't move from the enclosed thread group");
1335 }
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1336 thgroup_lock(old_tg);
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1337 rb_ary_delete(old_tg->threads, thread);
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1338 thgroup_unlock(old_tg);
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1339 }
1340
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1341 thgroup_lock(new_tg);
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1342 rb_ary_push(new_tg->threads, thread);
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1343 thgroup_unlock(new_tg);
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1344 GC_WB(&t->group, group);
1345
1346 return group;
1347 }
1348
1349 VALUE
1350 rb_thgroup_add(VALUE group, VALUE thread)
1351 {
1352 return thgroup_add(group, 0, thread);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1353 }
1354
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1355 void
1356 rb_thread_remove_from_group(VALUE thread)
1357 {
1358 rb_vm_thread_t *t = GetThreadPtr(thread);
d604765 don't always assume that a thread as a group
Laurent Sansonetti authored
1359 if (t->group != Qnil) {
1360 rb_thread_group_t *tg = GetThreadGroupPtr(t->group);
1361 thgroup_lock(tg);
1362 if (rb_ary_delete(tg->threads, thread) != thread) {
1363 printf("trying to remove a thread (%p) from a group that doesn't "\
1364 "contain it\n", (void *)thread);
1365 abort();
1366 }
1367 thgroup_unlock(tg);
1368 t->group = Qnil;
232a683 implemented VM cleanup + make sure Threads do not leak resources anymore
Laurent Sansonetti authored
1369 }
1370 }
1371
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1372 /*
1373 * Document-class: Mutex
1374 *
1375 * Mutex implements a simple semaphore that can be used to coordinate access to
1376 * shared data from multiple concurrent threads.
1377 *
1378 * Example:
1379 *
1380 * require 'thread'
1381 * semaphore = Mutex.new
1382 *
1383 * a = Thread.new {
1384 * semaphore.synchronize {
1385 * # access shared resource
1386 * }
1387 * }
1388 *
1389 * b = Thread.new {
1390 * semaphore.synchronize {
1391 * # access shared resource
1392 * }
1393 * }
1394 *
1395 */
1396
1397 /*
1398 * call-seq:
1399 * Mutex.new => mutex
1400 *
1401 * Creates a new Mutex
1402 */
43ad84f some mutex work
Laurent Sansonetti authored
1403
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1404 static VALUE
43ad84f some mutex work
Laurent Sansonetti authored
1405 mutex_s_alloc(VALUE self, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1406 {
43ad84f some mutex work
Laurent Sansonetti authored
1407 rb_vm_mutex_t *t = (rb_vm_mutex_t *)xmalloc(sizeof(rb_vm_mutex_t));
45e7828 fix a bug in {Thread,ThreadGroup,Mutex}#alloc where we would not retu…
Laurent Sansonetti authored
1408 return Data_Wrap_Struct(self, NULL, NULL, t);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1409 }
1410
43ad84f some mutex work
Laurent Sansonetti authored
1411 static VALUE
1412 mutex_initialize(VALUE self, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1413 {
459b19f more MT work
Laurent Sansonetti authored
1414 pthread_assert(pthread_mutex_init(&GetMutexPtr(self)->mutex, NULL));
43ad84f some mutex work
Laurent Sansonetti authored
1415 return self;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1416 }
1417
1418 /*
1419 * call-seq:
1420 * mutex.locked? => true or false
1421 *
1422 * Returns +true+ if this lock is currently held by some thread.
1423 */
1424
5113916 more MT work
Laurent Sansonetti authored
1425 static VALUE
1426 rb_mutex_locked_p(VALUE self, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1427 {
5113916 more MT work
Laurent Sansonetti authored
1428 return GetMutexPtr(self)->thread == 0 ? Qfalse : Qtrue;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1429 }
1430
1431 /*
1432 * call-seq:
1433 * mutex.try_lock => true or false
1434 *
1435 * Attempts to obtain the lock and returns immediately. Returns +true+ if the
1436 * lock was granted.
1437 */
1438
43ad84f some mutex work
Laurent Sansonetti authored
1439 static VALUE
1440 rb_mutex_trylock(VALUE self, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1441 {
8574616 `Mutex#try_unlock`: Add the mutex to the current thread mutexes on su…
Thibault Martin-Lagardette authored
1442 rb_vm_mutex_t *m = GetMutexPtr(self);
1443
1444 if (pthread_mutex_trylock(&m->mutex) == 0) {
1445 rb_vm_thread_t *current = GetThreadPtr(rb_vm_current_thread());
1446 m->thread = current;
1447 if (current->mutexes == Qnil) {
1448 GC_WB(&current->mutexes, rb_ary_new());
34d1835 fix a bug in Mutex and ThreadGroup where modifying internal array str…
Laurent Sansonetti authored
1449 OBJ_UNTRUST(current->mutexes);
8574616 `Mutex#try_unlock`: Add the mutex to the current thread mutexes on su…
Thibault Martin-Lagardette authored
1450 }
1451 rb_ary_push(current->mutexes, self);
5113916 more MT work
Laurent Sansonetti authored
1452 return Qtrue;
1453 }
8574616 `Mutex#try_unlock`: Add the mutex to the current thread mutexes on su…
Thibault Martin-Lagardette authored
1454
5113916 more MT work
Laurent Sansonetti authored
1455 return Qfalse;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1456 }
1457
1458 /*
1459 * call-seq:
5113916 more MT work
Laurent Sansonetti authored
1460 * mutex.lock => self
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1461 *
1462 * Attempts to grab the lock and waits if it isn't available.
1463 * Raises +ThreadError+ if +mutex+ was locked by the current thread.
1464 */
1465
5113916 more MT work
Laurent Sansonetti authored
1466 static VALUE
1467 rb_mutex_lock(VALUE self, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1468 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1469 rb_vm_thread_t *current = GetThreadPtr(rb_vm_current_thread());
5113916 more MT work
Laurent Sansonetti authored
1470 rb_vm_mutex_t *m = GetMutexPtr(self);
be9df8e @Watson1978 Thread#value should return nil when its thread was waited by Mutex#lo…
Watson1978 authored
1471 rb_vm_thread_status_t prev_status;
5113916 more MT work
Laurent Sansonetti authored
1472 if (m->thread == current) {
1473 rb_raise(rb_eThreadError, "deadlock; recursive locking");
1474 }
1475
be9df8e @Watson1978 Thread#value should return nil when its thread was waited by Mutex#lo…
Watson1978 authored
1476 prev_status = current->status;
1477 if (current->status == THREAD_ALIVE) {
1478 current->status = THREAD_SLEEP;
1479 }
1480 current->wait_for_mutex_lock = true;
459b19f more MT work
Laurent Sansonetti authored
1481 pthread_assert(pthread_mutex_lock(&m->mutex));
be9df8e @Watson1978 Thread#value should return nil when its thread was waited by Mutex#lo…
Watson1978 authored
1482 current->wait_for_mutex_lock = false;
1483 current->status = prev_status;
5113916 more MT work
Laurent Sansonetti authored
1484 m->thread = current;
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1485 if (current->mutexes == Qnil) {
1486 GC_WB(&current->mutexes, rb_ary_new());
34d1835 fix a bug in Mutex and ThreadGroup where modifying internal array str…
Laurent Sansonetti authored
1487 OBJ_UNTRUST(current->mutexes);
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1488 }
1489 rb_ary_push(current->mutexes, self);
5113916 more MT work
Laurent Sansonetti authored
1490
1491 return self;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1492 }
1493
1494 /*
1495 * call-seq:
1496 * mutex.unlock => self
1497 *
1498 * Releases the lock.
1499 * Raises +ThreadError+ if +mutex+ wasn't locked by the current thread.
1500 */
1501
82531fc fixed bugs in Mutex#synchronize and thread's unlock all mutexes logic…
Laurent Sansonetti authored
1502 static bool
1503 rb_mutex_can_unlock(rb_vm_mutex_t *m, bool raise)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1504 {
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1505 if (m->thread == NULL) {
82531fc fixed bugs in Mutex#synchronize and thread's unlock all mutexes logic…
Laurent Sansonetti authored
1506 if (!raise) {
1507 return false;
1508 }
5113916 more MT work
Laurent Sansonetti authored
1509 rb_raise(rb_eThreadError,
1510 "Attempt to unlock a mutex which is not locked");
1511 }
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1512 else if (m->thread != GetThreadPtr(rb_vm_current_thread())) {
82531fc fixed bugs in Mutex#synchronize and thread's unlock all mutexes logic…
Laurent Sansonetti authored
1513 if (!raise) {
1514 return false;
1515 }
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1516 rb_raise(rb_eThreadError,
1517 "Attempt to unlock a mutex which is locked by another thread");
1518 }
82531fc fixed bugs in Mutex#synchronize and thread's unlock all mutexes logic…
Laurent Sansonetti authored
1519 return true;
1520 }
1521
1522 static void
1523 rb_mutex_unlock0(VALUE self, bool assert_unlockable,
1524 bool delete_from_thread_mutexes)
1525 {
1526 rb_vm_mutex_t *m = GetMutexPtr(self);
1527 bool ok = rb_mutex_can_unlock(m, assert_unlockable);
1528 if (ok) {
1529 if (delete_from_thread_mutexes) {
1530 assert(m->thread->mutexes != Qnil);
1531 rb_ary_delete(m->thread->mutexes, self);
1532 }
1533 m->thread = NULL;
52f1b2b @jhemmelg Partial fix for ticket #542 - Attempt to unlock a mutex which is not …
jhemmelg authored
1534 pthread_assert(pthread_mutex_unlock(&m->mutex));
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1535 }
1536 }
5113916 more MT work
Laurent Sansonetti authored
1537
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1538 static VALUE
1539 rb_mutex_unlock(VALUE self, SEL sel)
1540 {
82531fc fixed bugs in Mutex#synchronize and thread's unlock all mutexes logic…
Laurent Sansonetti authored
1541 rb_mutex_unlock0(self, true, true);
5113916 more MT work
Laurent Sansonetti authored
1542 return self;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1543 }
1544
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1545 void
1546 rb_thread_unlock_all_mutexes(rb_vm_thread_t *thread)
1547 {
1548 if (thread->mutexes != Qnil) {
1549 int i, count = RARRAY_LEN(thread->mutexes);
1550 for (i = 0; i < count; i++) {
82531fc fixed bugs in Mutex#synchronize and thread's unlock all mutexes logic…
Laurent Sansonetti authored
1551 rb_mutex_unlock0(RARRAY_AT(thread->mutexes, i), false, false);
385a5b6 unlocked mutexes are now automatically unlocked once the thread that …
Laurent Sansonetti authored
1552 }
1553 rb_ary_clear(thread->mutexes);
1554 }
1555 }
1556
e7fa065 @Watson1978 invoke rb_mutex_lock surely with rb_ensure even if raise an exception.
Watson1978 authored
1557 static VALUE
1558 thread_sleep_forever(VALUE time)
1559 {
1560 rb_thread_sleep_forever();
1561 return Qnil;
1562 }
1563
1564 static VALUE
1565 thread_wait_for(VALUE time)
1566 {
1567 const struct timeval *t = (struct timeval *)time;
1568 rb_thread_wait_for(*t);
1569 return Qnil;
1570 }
1571
1572 static VALUE
1573 mutex_lock(VALUE self)
1574 {
1575 return rb_mutex_lock(self, 0);
1576 }
1577
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1578 /*
1579 * call-seq:
1580 * mutex.sleep(timeout = nil) => number
1581 *
1582 * Releases the lock and sleeps +timeout+ seconds if it is given and
1583 * non-nil or forever. Raises +ThreadError+ if +mutex+ wasn't locked by
1584 * the current thread.
1585 */
bbf842b @Watson1978 Thread#inspect will return string which copied receiver's status of t…
Watson1978 authored
1586
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1587 static VALUE
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1588 mutex_sleep(VALUE self, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1589 {
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1590 VALUE timeout;
1591 rb_scan_args(argc, argv, "01", &timeout);
1592
1593 rb_mutex_unlock(self, 0);
e7fa065 @Watson1978 invoke rb_mutex_lock surely with rb_ensure even if raise an exception.
Watson1978 authored
1594
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1595 time_t beg, end;
1596 beg = time(0);
1597
1598 if (timeout == Qnil) {
e7fa065 @Watson1978 invoke rb_mutex_lock surely with rb_ensure even if raise an exception.
Watson1978 authored
1599 rb_ensure(thread_sleep_forever, Qnil, mutex_lock, self);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1600 }
1601 else {
1602 struct timeval t = rb_time_interval(timeout);
e7fa065 @Watson1978 invoke rb_mutex_lock surely with rb_ensure even if raise an exception.
Watson1978 authored
1603 rb_ensure(thread_wait_for, (VALUE)&t, mutex_lock, self);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1604 }
1605
1606 end = time(0) - beg;
a8e8922 @jhemmelg Issue #542: Attempt to unlock a mutex which is not locked (ThreadError)
jhemmelg authored
1607 return INT2FIX(end);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1608 }
1609
1610 /*
1611 * call-seq:
1612 * mutex.synchronize { ... } => result of the block
1613 *
1614 * Obtains a lock, runs the block, and releases the lock when the block
1615 * completes. See the example under +Mutex+.
1616 */
1617
7c8e554 added a dummy Mutex#synchronize method that just yields, just to supp…
Laurent Sansonetti authored
1618 static VALUE
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1619 sync_body(VALUE a)
7c8e554 added a dummy Mutex#synchronize method that just yields, just to supp…
Laurent Sansonetti authored
1620 {
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1621 return rb_yield(Qundef);
1622 }
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1623
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1624 static VALUE
1625 sync_ensure(VALUE mutex)
1626 {
82531fc fixed bugs in Mutex#synchronize and thread's unlock all mutexes logic…
Laurent Sansonetti authored
1627 rb_mutex_unlock0(mutex, false, true);
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1628 return Qnil;
1629 }
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1630
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1631 static VALUE
1632 mutex_synchronize(VALUE self, SEL sel)
1633 {
1634 rb_mutex_lock(self, 0);
1635 return rb_ensure(sync_body, Qundef, sync_ensure, self);
7c8e554 added a dummy Mutex#synchronize method that just yields, just to supp…
Laurent Sansonetti authored
1636 }
1637
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1638 VALUE
1639 rb_thread_synchronize(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg)
1640 {
1641 // TODO
1642 return Qnil;
1643 }
1644
1645 /*
1646 * +Thread+ encapsulates the behavior of a thread of
1647 * execution, including the main thread of the Ruby script.
1648 *
1649 * In the descriptions of the methods in this class, the parameter _sym_
1650 * refers to a symbol, which is either a quoted string or a
1651 * +Symbol+ (such as <code>:name</code>).
1652 */
1653
1654 void
1655 Init_Thread(void)
1656 {
1657 rb_cThread = rb_define_class("Thread", rb_cObject);
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
1658 rb_objc_define_method(*(VALUE *)rb_cThread, "alloc", thread_s_alloc, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1659
affdd1a when a thread exists prematurely because of an exception, write a mes…
Laurent Sansonetti authored
1660 thread_finalize_imp_super = rb_objc_install_method2((Class)rb_cThread,
1661 "finalize", (IMP)thread_finalize_imp);
1662
f842fba implemented Thread.start/fork
Laurent Sansonetti authored
1663 rb_objc_define_method(*(VALUE *)rb_cThread, "start", thread_start, -1);
1664 rb_objc_define_method(*(VALUE *)rb_cThread, "fork", thread_start, -1);
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
1665 rb_objc_define_method(*(VALUE *)rb_cThread, "main", rb_thread_s_main, 0);
64f1345 expose Thread.current (even if it returns nil)
Laurent Sansonetti authored
1666 rb_objc_define_method(*(VALUE *)rb_cThread, "current", thread_s_current, 0);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1667 rb_objc_define_method(*(VALUE *)rb_cThread, "stop", rb_thread_stop, 0);
8a1aab0 implement Thread.kill and Thread.exit
Laurent Sansonetti authored
1668 rb_objc_define_method(*(VALUE *)rb_cThread, "kill", rb_thread_s_kill, 1);
1669 rb_objc_define_method(*(VALUE *)rb_cThread, "exit", rb_thread_exit, 0);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1670 rb_objc_define_method(*(VALUE *)rb_cThread, "pass", thread_s_pass, 0);
2ebb888 1st design changes for multithreaded MacRuby
Laurent Sansonetti authored
1671 rb_objc_define_method(*(VALUE *)rb_cThread, "list", rb_thread_list, 0);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1672 rb_objc_define_method(*(VALUE *)rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
1673 rb_objc_define_method(*(VALUE *)rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1674
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
1675 rb_objc_define_method(rb_cThread, "initialize", thread_initialize, -1);
c0c6a6d Thread#raise: added
Laurent Sansonetti authored
1676 rb_objc_define_method(rb_cThread, "raise", thread_raise_m, -1);
333801b added an experimental pthread-based implementation of Thread
Laurent Sansonetti authored
1677 rb_objc_define_method(rb_cThread, "join", thread_join_m, -1);
5113916 more MT work
Laurent Sansonetti authored
1678 rb_objc_define_method(rb_cThread, "value", thread_value, 0);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1679 rb_objc_define_method(rb_cThread, "kill", rb_thread_kill, 0);
1680 rb_objc_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
1681 rb_objc_define_method(rb_cThread, "exit", rb_thread_kill, 0);
1682 rb_objc_define_method(rb_cThread, "run", rb_thread_run, 0);
1683 rb_objc_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
84c7e85 implemented thread locals
Laurent Sansonetti authored
1684 rb_objc_define_method(rb_cThread, "[]", rb_thread_aref, 1);
1685 rb_objc_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
1686 rb_objc_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
1687 rb_objc_define_method(rb_cThread, "keys", rb_thread_keys, 0);
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
1688 rb_objc_define_method(rb_cThread, "priority", rb_thread_priority, 0);
1689 rb_objc_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1690 rb_objc_define_method(rb_cThread, "status", rb_thread_status, 0);
1691 rb_objc_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
1692 rb_objc_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
def4e10 exposing missing Thread methods
Laurent Sansonetti authored
1693 rb_objc_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
1694 rb_objc_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
1695 rb_objc_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1696 rb_objc_define_method(rb_cThread, "group", rb_thread_group, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1697
5113916 more MT work
Laurent Sansonetti authored
1698 rb_objc_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1699
afa7077 implemented ThreadGroup + rb_ensure()
Laurent Sansonetti authored
1700 rb_cThGroup = rb_define_class("ThreadGroup", rb_cObject);
1701 rb_objc_define_method(*(VALUE *)rb_cThGroup, "alloc", thgroup_s_alloc, 0);
1702 rb_objc_define_method(rb_cThGroup, "list", thgroup_list, 0);
1703 rb_objc_define_method(rb_cThGroup, "enclose", thgroup_enclose, 0);
1704 rb_objc_define_method(rb_cThGroup, "enclosed?", thgroup_enclosed_p, 0);
1705 rb_objc_define_method(rb_cThGroup, "add", thgroup_add, 1);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1706
1707 rb_cMutex = rb_define_class("Mutex", rb_cObject);
43ad84f some mutex work
Laurent Sansonetti authored
1708 rb_objc_define_method(*(VALUE *)rb_cMutex, "alloc", mutex_s_alloc, 0);
1709 rb_objc_define_method(rb_cMutex, "initialize", mutex_initialize, 0);
5113916 more MT work
Laurent Sansonetti authored
1710 rb_objc_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
1711 rb_objc_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
1712 rb_objc_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
1713 rb_objc_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
b7644c4 more work on MacRuby MT
Laurent Sansonetti authored
1714 rb_objc_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
7c8e554 added a dummy Mutex#synchronize method that just yields, just to supp…
Laurent Sansonetti authored
1715 rb_objc_define_method(rb_cMutex, "synchronize", mutex_synchronize, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
1716
1717 rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
1718 }
f283b86 add missing CRuby API rb_thread_blocking_region()
Laurent Sansonetti authored
1719
1720 VALUE
1721 rb_thread_blocking_region(rb_blocking_function_t *func, void *data1,
1722 rb_unblock_function_t *ubf, void *data2)
1723 {
1724 // For compatibility with CRuby. We do not have a global lock to release,
1725 // so we can just call the function directly.
1726 return func(data1);
1727 }
Something went wrong with that request. Please try again.