~ubuntu-branches/ubuntu/intrepid/ruby1.9/intrepid-updates

« back to all changes in this revision

Viewing changes to thread.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-09-04 16:01:17 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20070904160117-i15zckg2nhxe9fyw
Tags: 1.9.0+20070830-2ubuntu1
* Sync from Debian; remaining changes:
  - Add -g to CFLAGS.
* Fixes build failure on ia64.
* Fixes build failure with gcc-4.2 on lpia.
* Robustify check for target_os, fixing build failure on lpia.
* Set Ubuntu maintainer address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
  thread.c -
4
4
 
5
 
  $Author: nobu $
6
 
  $Date: 2007-06-05 13:25:10 +0900 (火, 05  6月 2007) $
 
5
  $Author: ko1 $
 
6
  $Date: 2007-08-28 01:48:14 +0900 (火, 28  8月 2007) $
7
7
 
8
8
  Copyright (C) 2004-2006 Koichi Sasada
9
9
 
80
80
 
81
81
#define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
82
82
 
83
 
static rb_unblock_function_t* set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func);
84
 
static void clear_unblock_function(rb_thread_t *th);
85
 
 
86
 
NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
87
 
NOINLINE(void rb_gc_save_machine_context(rb_thread_t *));
 
83
static void set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *ptr,
 
84
                                 rb_unblock_function_t **oldfunc, void **oldptr);
88
85
 
89
86
#define GVL_UNLOCK_BEGIN() do { \
90
87
  rb_thread_t *_th_stored = GET_THREAD(); \
96
93
  rb_thread_set_current(_th_stored); \
97
94
} while(0)
98
95
 
99
 
#define BLOCKING_REGION(exec, ubf) do { \
 
96
#define BLOCKING_REGION(exec, ubf, ubfarg) do { \
100
97
    rb_thread_t *__th = GET_THREAD(); \
101
98
    int __prev_status = __th->status; \
102
 
    rb_unblock_function_t *__oldubf = set_unblock_function(__th, ubf); \
 
99
    rb_unblock_function_t *__oldubf; \
 
100
    void *__oldubfarg; \
 
101
    set_unblock_function(__th, ubf, ubfarg, &__oldubf, &__oldubfarg); \
103
102
    __th->status = THREAD_STOPPED; \
104
103
    thread_debug("enter blocking region (%p)\n", __th); \
105
104
    GVL_UNLOCK_BEGIN(); {\
108
107
    GVL_UNLOCK_END(); \
109
108
    thread_debug("leave blocking region (%p)\n", __th); \
110
109
    remove_signal_thread_list(__th); \
111
 
    set_unblock_function(__th, __oldubf); \
 
110
    set_unblock_function(__th, __oldubf, __oldubfarg, 0, 0); \
112
111
    if (__th->status == THREAD_STOPPED) { \
113
112
        __th->status = __prev_status; \
114
113
    } \
141
140
#define thread_debug if(0)printf
142
141
#endif
143
142
 
 
143
#ifndef __ia64
 
144
#define thread_start_func_2(th, st, rst) thread_start_func_2(th, st)
 
145
#endif
 
146
NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start,
 
147
                                        VALUE *register_stack_start));
 
148
 
144
149
#if   defined(_WIN32)
145
150
#include "thread_win32.ci"
146
151
 
189
194
#endif
190
195
 
191
196
 
192
 
static rb_unblock_function_t *
193
 
set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func)
 
197
static void
 
198
set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
 
199
                     rb_unblock_function_t **oldfunc, void **oldarg)
194
200
{
195
 
    rb_unblock_function_t *oldfunc;
196
 
 
197
201
  check_ints:
198
202
    RUBY_VM_CHECK_INTS(); /* check signal or so */
199
203
    native_mutex_lock(&th->interrupt_lock);
202
206
        goto check_ints;
203
207
    }
204
208
    else {
205
 
        oldfunc = th->unblock_function;
 
209
        if (oldfunc) *oldfunc = th->unblock_function;
 
210
        if (oldarg) *oldarg = th->unblock_function_arg;
206
211
        th->unblock_function = func;
 
212
        th->unblock_function_arg = arg;
207
213
    }
208
214
    native_mutex_unlock(&th->interrupt_lock);
209
 
 
210
 
    return oldfunc;
211
 
}
212
 
 
213
 
static void
214
 
clear_unblock_function(rb_thread_t *th)
215
 
{
216
 
    native_mutex_lock(&th->interrupt_lock);
217
 
    th->unblock_function = 0;
218
 
    native_mutex_unlock(&th->interrupt_lock);
219
215
}
220
216
 
221
217
static void
224
220
    native_mutex_lock(&th->interrupt_lock);
225
221
    th->interrupt_flag = 1;
226
222
    if (th->unblock_function) {
227
 
        (th->unblock_function)(th);
 
223
        (th->unblock_function)(th, th->unblock_function_arg);
228
224
    }
229
225
    else {
230
226
        /* none */
265
261
    st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
266
262
 
267
263
    while (!rb_thread_alone()) {
268
 
        rb_thread_schedule();
 
264
        PUSH_TAG();
 
265
        if (EXEC_TAG() == 0) {
 
266
            rb_thread_schedule();
 
267
        }
 
268
        else {
 
269
            /* ignore exception */
 
270
        }
 
271
        POP_TAG();
269
272
    }
270
273
    system_working = 0;
271
274
}
276
279
    rb_thread_t *th = th_ptr;
277
280
    th->status = THREAD_KILLED;
278
281
    th->machine_stack_start = th->machine_stack_end = 0;
 
282
#ifdef __ia64
 
283
    th->machine_register_stack_start = th->machine_register_stack_end = 0;
 
284
#endif
279
285
    native_mutex_destroy(&th->interrupt_lock);
280
286
    native_thread_destroy(th);
281
287
}
282
288
 
 
289
extern void ruby_error_print(void);
 
290
static VALUE rb_thread_raise(int, VALUE *, rb_thread_t *);
 
291
 
283
292
static int
284
 
thread_start_func_2(rb_thread_t *th, VALUE *stack_start)
 
293
thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_start)
285
294
{
286
295
    int state;
287
296
    VALUE args = th->first_args;
288
297
    rb_proc_t *proc;
289
298
    rb_thread_t *join_th;
 
299
    rb_thread_t *main_th;
 
300
    VALUE errinfo = Qnil;
 
301
 
290
302
    th->machine_stack_start = stack_start;
 
303
#ifdef __ia64
 
304
    th->machine_register_stack_start = register_stack_start;
 
305
#endif
291
306
    th->thgroup = th->vm->thgroup_default;
292
307
    thread_debug("thread start: %p\n", th);
293
308
 
304
319
                    th->errinfo = Qnil;
305
320
                    th->local_lfp = proc->block.lfp;
306
321
                    th->local_svar = Qnil;
307
 
                    th->value = th_invoke_proc(th, proc, proc->block.self,
 
322
                    th->value = vm_invoke_proc(th, proc, proc->block.self,
308
323
                                               RARRAY_LEN(args), RARRAY_PTR(args));
309
324
                }
310
325
                else {
311
 
                    th->value = (*th->first_func)(th->first_func_arg);
 
326
                    th->value = (*th->first_func)((void *)th->first_args);
312
327
                }
313
328
            });
314
329
        }
315
330
        else {
 
331
            if (th->safe_level < 4 &&
 
332
                (th->vm->thread_abort_on_exception ||
 
333
                 th->abort_on_exception || RTEST(ruby_debug))) {
 
334
                errinfo = th->errinfo;
 
335
                if (NIL_P(errinfo)) errinfo = rb_errinfo();
 
336
            }
316
337
            th->value = Qnil;
317
338
        }
318
 
        TH_POP_TAG();
319
339
 
320
340
        th->status = THREAD_KILLED;
321
341
        thread_debug("thread end: %p\n", th);
 
342
 
 
343
        main_th = th->vm->main_thread;
 
344
        if (th != main_th) {
 
345
            if (TYPE(errinfo) == T_OBJECT) {
 
346
                /* treat with normal error object */
 
347
                rb_thread_raise(1, &errinfo, main_th);
 
348
            }
 
349
        }
 
350
        TH_POP_TAG();
 
351
 
322
352
        st_delete_wrap(th->vm->living_threads, th->self);
323
353
 
324
354
        /* wake up joinning threads */
325
355
        join_th = th->join_list_head;
326
356
        while (join_th) {
 
357
            if (join_th == main_th) errinfo = Qnil;
327
358
            rb_thread_interrupt(join_th);
328
359
            join_th = join_th->join_list_next;
329
360
        }
331
362
    }
332
363
    thread_cleanup_func(th);
333
364
    native_mutex_unlock(&th->vm->global_interpreter_lock);
 
365
 
334
366
    return 0;
335
367
}
336
368
 
337
369
static VALUE
338
 
thread_create_core(VALUE klass, VALUE args, VALUE (*fn)(ANYARGS), void *arg)
 
370
thread_create_core(VALUE klass, VALUE args, VALUE (*fn)(ANYARGS))
339
371
{
340
372
    rb_thread_t *th;
341
373
    VALUE thval;
348
380
    th->first_args = args;
349
381
    th->first_proc = fn ? Qfalse : rb_block_proc();
350
382
    th->first_func = fn;
351
 
    th->first_func_arg = arg;
 
383
 
 
384
    th->priority = GET_THREAD()->priority;
352
385
 
353
386
    native_mutex_initialize(&th->interrupt_lock);
354
387
    /* kick thread */
370
403
static VALUE
371
404
thread_s_new(VALUE klass, VALUE args)
372
405
{
373
 
    return thread_create_core(klass, args, 0, 0);
 
406
    return thread_create_core(klass, args, 0);
374
407
}
375
408
 
376
409
VALUE
377
410
rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
378
411
{
379
 
    return thread_create_core(rb_cThread, 0, fn, arg);
 
412
    return thread_create_core(rb_cThread, (VALUE)arg, fn);
380
413
}
381
414
 
382
415
 
383
416
/* +infty, for this purpose */
384
417
#define DELAY_INFTY 1E30
385
418
 
386
 
VALUE th_make_jump_tag_but_local_jump(int state, VALUE val);
387
 
 
388
419
static VALUE
389
420
thread_join(rb_thread_t *target_th, double delay)
390
421
{
391
422
    rb_thread_t *th = GET_THREAD();
392
423
    double now, limit = timeofday() + delay;
393
424
 
394
 
    thread_debug("thread_join (thid: %p)\n", target_th->thread_id);
 
425
    thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
395
426
 
396
427
    if (target_th->status != THREAD_KILLED) {
397
428
        th->join_list_next = target_th->join_list_head;
406
437
            now = timeofday();
407
438
            if (now > limit) {
408
439
                thread_debug("thread_join: timeout (thid: %p)\n",
409
 
                             target_th->thread_id);
 
440
                             (void *)target_th->thread_id);
410
441
                return Qnil;
411
442
            }
412
443
            sleep_wait_for_interrupt(th, limit - now);
413
444
        }
414
445
        thread_debug("thread_join: interrupted (thid: %p)\n",
415
 
                     target_th->thread_id);
 
446
                     (void *)target_th->thread_id);
416
447
    }
417
448
 
418
449
    thread_debug("thread_join: success (thid: %p)\n",
419
 
                 target_th->thread_id);
 
450
                 (void *)target_th->thread_id);
420
451
 
421
452
    if (target_th->errinfo != Qnil) {
422
453
        VALUE err = target_th->errinfo;
425
456
            /* */
426
457
        }
427
458
        else if (TYPE(target_th->errinfo) == T_NODE) {
428
 
            rb_exc_raise(th_make_jump_tag_but_local_jump(
 
459
            rb_exc_raise(vm_make_jump_tag_but_local_jump(
429
460
                GET_THROWOBJ_STATE(err), GET_THROWOBJ_VAL(err)));
430
461
        }
431
462
        else {
632
663
 
633
664
VALUE
634
665
rb_thread_blocking_region(
635
 
    rb_blocking_function_t *func, void *data,
636
 
    rb_unblock_function_t *ubf)
 
666
    rb_blocking_function_t *func, void *data1,
 
667
    rb_unblock_function_t *ubf, void *data2)
637
668
{
638
669
    VALUE val;
639
670
    rb_thread_t *th = GET_THREAD();
641
672
    if (ubf == RB_UBF_DFL) {
642
673
        ubf = ubf_select;
643
674
    }
 
675
 
644
676
    BLOCKING_REGION({
645
 
        val = func(th, data);
646
 
    }, ubf);
 
677
        val = func(th, data1);
 
678
    }, ubf, data2);
647
679
 
648
680
    return val;
649
681
}
700
732
            th->thrown_errinfo = 0;
701
733
            thread_debug("rb_thread_execute_interrupts: %ld\n", err);
702
734
 
703
 
            if (err == eKillSignal) {
704
 
                th->errinfo = INT2FIX(TAG_FATAL);
705
 
                TH_JUMP_TAG(th, TAG_FATAL);
706
 
            }
707
 
            else if (err == eTerminateSignal) {
708
 
                /* rewind to toplevel stack */
709
 
                while (th->tag->prev) {
710
 
                    th->tag = th->tag->prev;
711
 
                }
712
 
 
 
735
            if (err == eKillSignal || err == eTerminateSignal) {
713
736
                th->errinfo = INT2FIX(TAG_FATAL);
714
737
                TH_JUMP_TAG(th, TAG_FATAL);
715
738
            }
745
768
{
746
769
    VALUE exc;
747
770
 
 
771
  again:
748
772
    if (rb_thread_dead(th)) {
749
773
        return Qnil;
750
774
    }
751
775
 
 
776
    if (th->thrown_errinfo != 0 || th->raised_flag) {
 
777
        rb_thread_schedule();
 
778
        goto again;
 
779
    }
 
780
 
752
781
    exc = rb_make_exception(argc, argv);
753
 
    /* TODO: need synchronization if run threads in parallel */
754
782
    th->thrown_errinfo = exc;
755
783
    rb_thread_ready(th);
756
784
    return Qnil;
1722
1750
                    if (except) *except = orig_except;
1723
1751
                    wait = &wait_100ms;
1724
1752
                } while (__th->interrupt_flag == 0 && (timeout == 0 || subst(timeout, &wait_100ms)));
1725
 
            }, 0);
 
1753
            }, 0, 0);
1726
1754
        } while (result == 0 && (timeout == 0 || subst(timeout, &wait_100ms)));
1727
1755
    }
1728
1756
#else
1729
1757
    BLOCKING_REGION({
1730
1758
        result = select(n, read, write, except, timeout);
1731
1759
        if (result < 0) lerrno = errno;
1732
 
    }, ubf_select);
 
1760
    }, ubf_select, 0);
1733
1761
#endif
1734
1762
 
1735
1763
    errno = lerrno;
1777
1805
            result = do_select(fd + 1, 0, rb_fd_ptr(&set), 0, 0);
1778
1806
        }
1779
1807
 
 
1808
        rb_fd_term(&set);
 
1809
 
1780
1810
        if (result < 0 && errno != EBADF) {
1781
1811
            rb_sys_fail(0);
1782
1812
        }
1820
1850
 * for GC
1821
1851
 */
1822
1852
 
 
1853
#ifdef USE_CONSERVATIVE_STACK_END
1823
1854
void
1824
1855
rb_gc_set_stack_end(VALUE **stack_end_p)
1825
1856
{
1826
1857
    VALUE stack_end;
1827
1858
    *stack_end_p = &stack_end;
1828
1859
}
 
1860
#endif
1829
1861
 
1830
1862
void
1831
1863
rb_gc_save_machine_context(rb_thread_t *th)
1832
1864
{
1833
 
    rb_gc_set_stack_end(&th->machine_stack_end);
 
1865
    SET_MACHINE_STACK_END(&th->machine_stack_end);
 
1866
#ifdef __ia64
 
1867
    th->machine_register_stack_end = rb_ia64_bsp();
 
1868
#endif
1834
1869
    setjmp(th->machine_regs);
1835
1870
}
1836
1871
 
1968
2003
thgroup_list(VALUE group)
1969
2004
{
1970
2005
    VALUE ary = rb_ary_new();
1971
 
    struct thgroup_list_params param = {
1972
 
        ary, group,
1973
 
    };
 
2006
    struct thgroup_list_params param;
 
2007
    
 
2008
    param.ary = ary;
 
2009
    param.group = group;
1974
2010
    st_foreach(GET_THREAD()->vm->living_threads, thgroup_list_i, (st_data_t) & param);
1975
2011
    return ary;
1976
2012
}
2113
2149
 */
2114
2150
 
2115
2151
typedef struct mutex_struct {
2116
 
    rb_thread_t *th;
2117
2152
    rb_thread_lock_t lock;
 
2153
    rb_thread_cond_t cond;
 
2154
    rb_thread_t volatile *th;
 
2155
    volatile int cond_waiting;
2118
2156
} mutex_t;
2119
2157
 
2120
 
#define GetMutexVal(obj, tobj) \
 
2158
#define GetMutexPtr(obj, tobj) \
2121
2159
  Data_Get_Struct(obj, mutex_t, tobj)
2122
2160
 
2123
2161
static void
2136
2174
{
2137
2175
    if (ptr) {
2138
2176
        mutex_t *mutex = ptr;
2139
 
        if (mutex->th) {
2140
 
            native_mutex_unlock(&mutex->lock);
2141
 
        }
2142
2177
        native_mutex_destroy(&mutex->lock);
 
2178
        native_cond_destroy(&mutex->cond);
2143
2179
    }
2144
2180
    ruby_xfree(ptr);
2145
2181
}
2151
2187
    mutex_t *mutex;
2152
2188
 
2153
2189
    obj = Data_Make_Struct(klass, mutex_t, mutex_mark, mutex_free, mutex);
2154
 
    mutex->th = 0;
2155
2190
    native_mutex_initialize(&mutex->lock);
 
2191
    native_cond_initialize(&mutex->cond);
2156
2192
    return obj;
2157
2193
}
2158
2194
 
2184
2220
rb_mutex_locked_p(VALUE self)
2185
2221
{
2186
2222
    mutex_t *mutex;
2187
 
    GetMutexVal(self, mutex);
 
2223
    GetMutexPtr(self, mutex);
2188
2224
    return mutex->th ? Qtrue : Qfalse;
2189
2225
}
2190
2226
 
2196
2232
 * lock was granted.
2197
2233
 */
2198
2234
VALUE
2199
 
rb_mutex_try_lock(VALUE self)
 
2235
rb_mutex_trylock(VALUE self)
2200
2236
{
2201
2237
    mutex_t *mutex;
2202
 
    GetMutexVal(self, mutex);
 
2238
    VALUE locked = Qfalse;
 
2239
    GetMutexPtr(self, mutex);
2203
2240
 
2204
2241
    if (mutex->th == GET_THREAD()) {
2205
2242
        rb_raise(rb_eThreadError, "deadlock; recursive locking");
2206
2243
    }
2207
2244
 
2208
 
    if (native_mutex_trylock(&mutex->lock) != EBUSY) {
 
2245
    native_mutex_lock(&mutex->lock);
 
2246
    if (mutex->th == 0) {
2209
2247
        mutex->th = GET_THREAD();
2210
 
        return Qtrue;
2211
 
    }
2212
 
    else {
2213
 
        return Qfalse;
2214
 
    }
 
2248
        locked = Qtrue;
 
2249
    }
 
2250
    native_mutex_unlock(&mutex->lock);
 
2251
 
 
2252
    return locked;
 
2253
}
 
2254
 
 
2255
static VALUE
 
2256
lock_func(rb_thread_t *th, void *ptr)
 
2257
{
 
2258
    int locked = 0;
 
2259
    mutex_t *mutex = (mutex_t *)ptr;
 
2260
 
 
2261
    while (locked == 0) {
 
2262
        native_mutex_lock(&mutex->lock);
 
2263
 
 
2264
        if (mutex->th == 0) {
 
2265
            mutex->th = th;
 
2266
            locked = 1;
 
2267
        }
 
2268
        else {
 
2269
            mutex->cond_waiting++;
 
2270
            native_cond_wait(&mutex->cond, &mutex->lock);
 
2271
 
 
2272
            if (th->interrupt_flag) {
 
2273
                locked = 1;
 
2274
            }
 
2275
            else if (mutex->th == 0) {
 
2276
                mutex->th = th;
 
2277
                locked = 1;
 
2278
            }
 
2279
        }
 
2280
 
 
2281
        native_mutex_unlock(&mutex->lock);
 
2282
    }
 
2283
    return Qnil;
 
2284
}
 
2285
 
 
2286
static void
 
2287
lock_interrupt(rb_thread_t *th, void *ptr)
 
2288
{
 
2289
    mutex_t *mutex = (mutex_t *)ptr;
 
2290
    native_mutex_lock(&mutex->lock);
 
2291
    if (mutex->cond_waiting > 0) {
 
2292
        native_cond_broadcast(&mutex->cond);
 
2293
        mutex->cond_waiting = 0;
 
2294
    }
 
2295
    native_mutex_unlock(&mutex->lock);
2215
2296
}
2216
2297
 
2217
2298
/*
2224
2305
VALUE
2225
2306
rb_mutex_lock(VALUE self)
2226
2307
{
2227
 
    mutex_t *mutex;
2228
 
    GetMutexVal(self, mutex);
2229
 
 
2230
 
    if (mutex->th == GET_THREAD()) {
2231
 
        rb_raise(rb_eThreadError, "deadlock; recursive locking");
2232
 
    }
2233
 
 
2234
 
    if (native_mutex_trylock(&mutex->lock) != 0) {
2235
 
        /* can't cancel */
2236
 
        GVL_UNLOCK_BEGIN();
2237
 
        native_mutex_lock(&mutex->lock);
2238
 
        GVL_UNLOCK_END();
2239
 
    }
2240
 
 
2241
 
    mutex->th = GET_THREAD();
 
2308
    if (rb_mutex_trylock(self) == Qfalse) {
 
2309
        mutex_t *mutex;
 
2310
        rb_thread_t *th = GET_THREAD();
 
2311
        GetMutexPtr(self, mutex);
 
2312
 
 
2313
        while (mutex->th != th) {
 
2314
            rb_thread_blocking_region(lock_func, mutex, lock_interrupt, mutex);
 
2315
            RUBY_VM_CHECK_INTS();
 
2316
        }
 
2317
    }
 
2318
 
2242
2319
    return self;
2243
2320
}
2244
2321
 
2253
2330
rb_mutex_unlock(VALUE self)
2254
2331
{
2255
2332
    mutex_t *mutex;
2256
 
    GetMutexVal(self, mutex);
 
2333
    GetMutexPtr(self, mutex);
2257
2334
 
2258
2335
    if (mutex->th != GET_THREAD()) {
2259
2336
        rb_raise(rb_eThreadError,
2260
2337
                 "Attempt to unlock a mutex which is locked by another thread");
2261
2338
    }
 
2339
 
 
2340
    native_mutex_lock(&mutex->lock);
2262
2341
    mutex->th = 0;
 
2342
    if (mutex->cond_waiting > 0) {
 
2343
        /* waiting thread */
 
2344
        native_cond_signal(&mutex->cond);
 
2345
        mutex->cond_waiting--;
 
2346
    }
2263
2347
    native_mutex_unlock(&mutex->lock);
 
2348
 
2264
2349
    return self;
2265
2350
}
2266
2351
 
2355
2440
    int woken = 0;
2356
2441
    rb_thread_list_t *q;
2357
2442
 
2358
 
    while (q = *list) {
 
2443
    while ((q = *list) != NULL) {
2359
2444
        rb_thread_t *th = q->th;
2360
2445
 
2361
2446
        *list = q->next;
2712
2797
static VALUE
2713
2798
set_trace_func(VALUE obj, VALUE trace)
2714
2799
{
2715
 
    rb_vm_t *vm = GET_VM();
2716
2800
    rb_remove_event_hook(call_trace_func);
2717
2801
 
2718
2802
    if (NIL_P(trace)) {
2785
2869
    }
2786
2870
}
2787
2871
 
 
2872
VALUE ruby_suppress_tracing(VALUE (*func)(ANYARGS), VALUE arg);
 
2873
 
 
2874
struct call_trace_func_args {
 
2875
    rb_event_flag_t event;
 
2876
    VALUE proc;
 
2877
    VALUE self;
 
2878
    ID id;
 
2879
    VALUE klass;
 
2880
};
 
2881
 
 
2882
static VALUE
 
2883
call_trace_proc(VALUE args)
 
2884
{
 
2885
    struct call_trace_func_args *p = (struct call_trace_func_args *)args;
 
2886
    VALUE eventname = rb_str_new2(get_event_name(p->event));
 
2887
    VALUE filename = rb_str_new2(rb_sourcefile());
 
2888
    int line = rb_sourceline();
 
2889
 
 
2890
    return rb_proc_call(p->proc, rb_ary_new3(6,
 
2891
                                             eventname, filename, INT2FIX(line),
 
2892
                                             p->id ? ID2SYM(p->id) : Qnil,
 
2893
                                             p->self ? rb_binding_new() : Qnil,
 
2894
                                             p->klass ? p->klass : Qnil));
 
2895
}
 
2896
 
2788
2897
static void
2789
2898
call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
2790
2899
{
 
2900
    struct call_trace_func_args args;
 
2901
    
 
2902
    args.event = event;
 
2903
    args.proc = proc;
 
2904
    args.self = self;
 
2905
    args.id = id;
 
2906
    args.klass = klass;
 
2907
    ruby_suppress_tracing(call_trace_proc, (VALUE)&args);
 
2908
}
 
2909
 
 
2910
VALUE
 
2911
ruby_suppress_tracing(VALUE (*func)(ANYARGS), VALUE arg)
 
2912
{
2791
2913
    rb_thread_t *th = GET_THREAD();
2792
2914
    int state, raised;
2793
 
    VALUE eventname = rb_str_new2(get_event_name(event));
2794
 
    VALUE filename = rb_str_new2(rb_sourcefile());
2795
 
    int line = rb_sourceline();
 
2915
    VALUE result = Qnil;
2796
2916
 
2797
2917
    if (th->tracing) {
2798
 
        return;
 
2918
        return Qnil;
2799
2919
    }
2800
2920
    else {
2801
2921
        th->tracing = 1;
2805
2925
 
2806
2926
    PUSH_TAG();
2807
2927
    if ((state = EXEC_TAG()) == 0) {
2808
 
        proc_invoke(proc, rb_ary_new3(6,
2809
 
                                      eventname, filename, INT2FIX(line),
2810
 
                                      id ? ID2SYM(id) : Qnil,
2811
 
                                      self ? rb_binding_new() : Qnil,
2812
 
                                      klass ? klass : Qnil), Qundef, 0);
 
2928
        result = (*func)(arg);
2813
2929
    }
2814
2930
 
2815
2931
    if (raised) {
2821
2937
    if (state) {
2822
2938
        JUMP_TAG(state);
2823
2939
    }
 
2940
 
 
2941
    return result;
2824
2942
}
2825
2943
 
2826
2944
/*
2897
3015
    rb_define_alloc_func(rb_cMutex, mutex_alloc);
2898
3016
    rb_define_method(rb_cMutex, "initialize", mutex_initialize, 0);
2899
3017
    rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
2900
 
    rb_define_method(rb_cMutex, "try_lock", rb_mutex_try_lock, 0);
 
3018
    rb_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
2901
3019
    rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
2902
3020
    rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
2903
3021
    rb_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
2904
 
    yarvcore_eval(Qnil, rb_str_new2(
2905
 
        "class Mutex;"
2906
 
        "  def synchronize; self.lock; yield; ensure; self.unlock; end;"
2907
 
        "end;"), rb_str_new2("<preload>"), INT2FIX(1));
2908
3022
 
2909
3023
    recursive_key = rb_intern("__recursive_key__");
2910
3024
    rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
2930
3044
    rb_thread_create_timer_thread();
2931
3045
}
2932
3046
 
2933
 
VALUE
 
3047
int
2934
3048
is_ruby_native_thread(void)
2935
3049
{
2936
 
    return Qtrue;
 
3050
    rb_thread_t *rb_thread_check_ptr(rb_thread_t *ptr);
 
3051
    rb_thread_t *th = ruby_thread_from_native();
 
3052
 
 
3053
    return th ? Qtrue : Qfalse;
2937
3054
}