~ubuntu-branches/ubuntu/quantal/ruby1.9.1/quantal

« back to all changes in this revision

Viewing changes to thread.c

  • Committer: Bazaar Package Importer
  • Author(s): Lucas Nussbaum
  • Date: 2011-09-24 19:16:17 UTC
  • mfrom: (1.1.8 upstream) (13.1.7 experimental)
  • Revision ID: james.westby@ubuntu.com-20110924191617-o1qz4rcmqjot8zuy
Tags: 1.9.3~rc1-1
* New upstream release: 1.9.3 RC1.
  + Includes load.c fixes. Closes: #639959.
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
  thread.c -
4
4
 
5
 
  $Author: yugui $
 
5
  $Author: kosaki $
6
6
 
7
7
  Copyright (C) 2004-2007 Koichi Sasada
8
8
 
46
46
 
47
47
#include "eval_intern.h"
48
48
#include "gc.h"
 
49
#include "internal.h"
 
50
#include "ruby/io.h"
49
51
 
50
52
#ifndef USE_NATIVE_THREAD_PRIORITY
51
53
#define USE_NATIVE_THREAD_PRIORITY 0
64
66
static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec);
65
67
static void sleep_forever(rb_thread_t *th, int nodeadlock);
66
68
static double timeofday(void);
67
 
struct timeval rb_time_interval(VALUE);
68
69
static int rb_threadptr_dead(rb_thread_t *th);
69
70
 
70
71
static void rb_check_deadlock(rb_vm_t *vm);
71
72
 
72
 
int rb_signal_buff_size(void);
73
 
void rb_signal_exec(rb_thread_t *th, int sig);
74
 
void rb_disable_interrupt(void);
75
 
void rb_thread_stop_timer_thread(void);
76
 
 
77
 
static const VALUE eKillSignal = INT2FIX(0);
78
 
static const VALUE eTerminateSignal = INT2FIX(1);
 
73
#define eKillSignal INT2FIX(0)
 
74
#define eTerminateSignal INT2FIX(1)
79
75
static volatile int system_working = 1;
80
76
 
 
77
#define closed_stream_error GET_VM()->special_exceptions[ruby_error_closed_stream]
 
78
 
81
79
inline static void
82
80
st_delete_wrap(st_table *table, st_data_t key)
83
81
{
108
106
#define GVL_UNLOCK_BEGIN() do { \
109
107
  rb_thread_t *_th_stored = GET_THREAD(); \
110
108
  RB_GC_SAVE_MACHINE_CONTEXT(_th_stored); \
111
 
  native_mutex_unlock(&_th_stored->vm->global_vm_lock)
 
109
  gvl_release(_th_stored->vm);
112
110
 
113
111
#define GVL_UNLOCK_END() \
114
 
  native_mutex_lock(&_th_stored->vm->global_vm_lock); \
 
112
  gvl_acquire(_th_stored->vm, _th_stored); \
115
113
  rb_thread_set_current(_th_stored); \
116
114
} while(0)
117
115
 
118
 
#define BLOCKING_REGION_CORE(exec) do { \
119
 
    GVL_UNLOCK_BEGIN(); {\
120
 
            exec; \
121
 
    } \
122
 
    GVL_UNLOCK_END(); \
123
 
} while(0);
124
 
 
125
116
#define blocking_region_begin(th, region, func, arg) \
126
117
  do { \
127
118
    (region)->prev_status = (th)->status; \
130
121
    (th)->status = THREAD_STOPPED; \
131
122
    thread_debug("enter blocking region (%p)\n", (void *)(th)); \
132
123
    RB_GC_SAVE_MACHINE_CONTEXT(th); \
133
 
    native_mutex_unlock(&(th)->vm->global_vm_lock); \
 
124
    gvl_release((th)->vm); \
134
125
  } while (0)
135
126
 
136
127
#define BLOCKING_REGION(exec, ubf, ubfarg) do { \
137
128
    rb_thread_t *__th = GET_THREAD(); \
138
129
    struct rb_blocking_region_buffer __region; \
139
 
    blocking_region_begin(__th, &__region, ubf, ubfarg); \
 
130
    blocking_region_begin(__th, &__region, (ubf), (ubfarg)); \
140
131
    exec; \
141
132
    blocking_region_end(__th, &__region); \
142
133
    RUBY_VM_CHECK_INTS(); \
252
243
#endif
253
244
 
254
245
void
 
246
rb_vm_gvl_destroy(rb_vm_t *vm)
 
247
{
 
248
    gvl_release(vm);
 
249
    gvl_destroy(vm);
 
250
}
 
251
 
 
252
void
255
253
rb_thread_lock_unlock(rb_thread_lock_t *lock)
256
254
{
257
255
    native_mutex_unlock(lock);
329
327
    rb_thread_lock_t lock;
330
328
    rb_thread_cond_t cond;
331
329
    struct rb_thread_struct volatile *th;
332
 
    volatile int cond_waiting, cond_notified;
 
330
    int cond_waiting;
333
331
    struct rb_mutex_struct *next_mutex;
334
 
} mutex_t;
335
 
 
336
 
static void rb_mutex_unlock_all(mutex_t *mutex, rb_thread_t *th);
337
 
static void rb_mutex_abandon_all(mutex_t *mutexes);
 
332
} rb_mutex_t;
 
333
 
 
334
static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
 
335
static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th);
 
336
 
 
337
void
 
338
rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
 
339
{
 
340
    const char *err;
 
341
    rb_mutex_t *mutex;
 
342
    rb_mutex_t *mutexes = th->keeping_mutexes;
 
343
 
 
344
    while (mutexes) {
 
345
        mutex = mutexes;
 
346
        /* rb_warn("mutex #<%p> remains to be locked by terminated thread",
 
347
                mutexes); */
 
348
        mutexes = mutex->next_mutex;
 
349
        err = rb_mutex_unlock_th(mutex, th);
 
350
        if (err) rb_bug("invalid keeping_mutexes: %s", err);
 
351
    }
 
352
}
338
353
 
339
354
void
340
355
rb_thread_terminate_all(void)
348
363
    }
349
364
 
350
365
    /* unlock all locking mutexes */
351
 
    if (th->keeping_mutexes) {
352
 
        rb_mutex_unlock_all(th->keeping_mutexes, GET_THREAD());
353
 
    }
 
366
    rb_threadptr_unlock_all_locking_mutexes(th);
354
367
 
355
368
    thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)th);
356
369
    st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
 
370
    vm->inhibit_thread_creation = 1;
357
371
 
358
372
    while (!rb_thread_alone()) {
359
373
        PUSH_TAG();
365
379
        }
366
380
        POP_TAG();
367
381
    }
368
 
    rb_thread_stop_timer_thread();
369
 
}
370
 
 
371
 
static void
372
 
thread_unlock_all_locking_mutexes(rb_thread_t *th)
373
 
{
374
 
    if (th->keeping_mutexes) {
375
 
        rb_mutex_unlock_all(th->keeping_mutexes, th);
376
 
        th->keeping_mutexes = NULL;
377
 
    }
378
382
}
379
383
 
380
384
static void
404
408
    if (atfork)
405
409
        return;
406
410
 
 
411
    native_mutex_destroy(&th->interrupt_lock);
407
412
    native_thread_destroy(th);
408
413
}
409
414
 
410
 
extern void ruby_error_print(void);
411
415
static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *);
412
 
void rb_thread_recycle_stack_release(VALUE *);
413
416
 
414
417
void
415
418
ruby_thread_init_stack(rb_thread_t *th)
440
443
#endif
441
444
    thread_debug("thread start: %p\n", (void *)th);
442
445
 
443
 
    native_mutex_lock(&th->vm->global_vm_lock);
 
446
    gvl_acquire(th->vm, th);
444
447
    {
445
448
        thread_debug("thread start (get lock): %p\n", (void *)th);
446
449
        rb_thread_set_current(th);
521
524
            join_th = join_th->join_list_next;
522
525
        }
523
526
 
524
 
        thread_unlock_all_locking_mutexes(th);
 
527
        rb_threadptr_unlock_all_locking_mutexes(th);
525
528
        if (th != main_th) rb_check_deadlock(th->vm);
526
529
 
527
530
        if (!th->root_fiber) {
534
537
    }
535
538
    else {
536
539
        thread_cleanup_func(th, FALSE);
537
 
        native_mutex_unlock(&th->vm->global_vm_lock);
 
540
        gvl_release(th->vm);
538
541
    }
539
542
 
540
543
    return 0;
581
584
{
582
585
    rb_thread_t *th;
583
586
    VALUE thread = rb_thread_alloc(klass);
 
587
 
 
588
    if (GET_VM()->inhibit_thread_creation)
 
589
        rb_raise(rb_eThreadError, "can't alloc thread");
 
590
 
584
591
    rb_obj_call_init(thread, argc, argv);
585
592
    GetThreadPtr(thread, th);
586
593
    if (!th->first_args) {
616
623
    }
617
624
    GetThreadPtr(thread, th);
618
625
    if (th->first_args) {
619
 
        VALUE rb_proc_location(VALUE self);
620
626
        VALUE proc = th->first_proc, line, loc;
621
627
        const char *file;
622
628
        if (!proc || !RTEST(loc = rb_proc_location(proc))) {
838
844
sleep_forever(rb_thread_t *th, int deadlockable)
839
845
{
840
846
    enum rb_thread_status prev_status = th->status;
 
847
    enum rb_thread_status status = deadlockable ? THREAD_STOPPED_FOREVER : THREAD_STOPPED;
841
848
 
842
 
    th->status = deadlockable ? THREAD_STOPPED_FOREVER : THREAD_STOPPED;
 
849
    th->status = status;
843
850
    do {
844
851
        if (deadlockable) {
845
852
            th->vm->sleeper++;
850
857
            th->vm->sleeper--;
851
858
        }
852
859
        RUBY_VM_CHECK_INTS();
853
 
    } while (th->status == THREAD_STOPPED_FOREVER);
 
860
    } while (th->status == status);
854
861
    th->status = prev_status;
855
862
}
856
863
 
985
992
int
986
993
rb_thread_check_trap_pending(void)
987
994
{
988
 
    return GET_THREAD()->exec_signal != 0;
 
995
    return rb_signal_buff_size() != 0;
989
996
}
990
997
 
991
998
/* This function can be called in blocking region. */
997
1004
    return RUBY_VM_INTERRUPTED(th);
998
1005
}
999
1006
 
1000
 
struct timeval rb_time_timeval(VALUE);
1001
 
 
1002
1007
void
1003
1008
rb_thread_sleep(int sec)
1004
1009
{
1005
1010
    rb_thread_wait_for(rb_time_timeval(INT2FIX(sec)));
1006
1011
}
1007
1012
 
1008
 
static void rb_threadptr_execute_interrupts_rec(rb_thread_t *, int);
 
1013
static void rb_threadptr_execute_interrupts_common(rb_thread_t *);
1009
1014
 
1010
1015
static void
1011
 
rb_thread_schedule_rec(int sched_depth)
 
1016
rb_thread_schedule_limits(unsigned long limits_us)
1012
1017
{
1013
1018
    thread_debug("rb_thread_schedule\n");
1014
1019
    if (!rb_thread_alone()) {
1015
1020
        rb_thread_t *th = GET_THREAD();
1016
1021
 
1017
 
        thread_debug("rb_thread_schedule/switch start\n");
1018
 
 
1019
 
        RB_GC_SAVE_MACHINE_CONTEXT(th);
1020
 
        native_mutex_unlock(&th->vm->global_vm_lock);
1021
 
        {
1022
 
            native_thread_yield();
 
1022
        if (th->running_time_us >= limits_us) {
 
1023
            thread_debug("rb_thread_schedule/switch start\n");
 
1024
            RB_GC_SAVE_MACHINE_CONTEXT(th);
 
1025
            gvl_yield(th->vm, th);
 
1026
            rb_thread_set_current(th);
 
1027
            thread_debug("rb_thread_schedule/switch done\n");
1023
1028
        }
1024
 
        native_mutex_lock(&th->vm->global_vm_lock);
1025
 
 
1026
 
        rb_thread_set_current(th);
1027
 
        thread_debug("rb_thread_schedule/switch done\n");
1028
 
 
1029
 
        if (!sched_depth && UNLIKELY(GET_THREAD()->interrupt_flag)) {
1030
 
            rb_threadptr_execute_interrupts_rec(GET_THREAD(), sched_depth+1);
1031
 
        }
1032
1029
    }
1033
1030
}
1034
1031
 
1035
1032
void
1036
1033
rb_thread_schedule(void)
1037
1034
{
1038
 
    rb_thread_schedule_rec(0);
 
1035
    rb_thread_schedule_limits(0);
 
1036
 
 
1037
    if (UNLIKELY(GET_THREAD()->interrupt_flag)) {
 
1038
        rb_threadptr_execute_interrupts_common(GET_THREAD());
 
1039
    }
1039
1040
}
1040
1041
 
1041
1042
/* blocking region */
1043
1044
static inline void
1044
1045
blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
1045
1046
{
1046
 
    native_mutex_lock(&th->vm->global_vm_lock);
 
1047
    gvl_acquire(th->vm, th);
1047
1048
    rb_thread_set_current(th);
1048
1049
    thread_debug("leave blocking region (%p)\n", (void *)th);
1049
1050
    remove_signal_thread_list(th);
1119
1120
    rb_thread_t *th = GET_THREAD();
1120
1121
    int saved_errno = 0;
1121
1122
 
 
1123
    th->waiting_fd = -1;
1122
1124
    if (ubf == RUBY_UBF_IO || ubf == RUBY_UBF_PROCESS) {
1123
1125
        ubf = ubf_select;
1124
1126
        data2 = th;
1133
1135
    return val;
1134
1136
}
1135
1137
 
 
1138
VALUE
 
1139
rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
 
1140
{
 
1141
    VALUE val;
 
1142
    rb_thread_t *th = GET_THREAD();
 
1143
    int saved_errno = 0;
 
1144
 
 
1145
    th->waiting_fd = fd;
 
1146
    BLOCKING_REGION({
 
1147
        val = func(data1);
 
1148
        saved_errno = errno;
 
1149
    }, ubf_select, th);
 
1150
    th->waiting_fd = -1;
 
1151
    errno = saved_errno;
 
1152
 
 
1153
    return val;
 
1154
}
 
1155
 
1136
1156
/* alias of rb_thread_blocking_region() */
1137
1157
 
1138
1158
VALUE
1190
1210
         */
1191
1211
 
1192
1212
        fprintf(stderr, "[BUG] rb_thread_call_with_gvl() is called by non-ruby thread\n");
1193
 
        exit(1);
 
1213
        exit(EXIT_FAILURE);
1194
1214
    }
1195
1215
 
1196
1216
    brb = (struct rb_blocking_region_buffer *)th->blocking_region_buffer;
1231
1251
}
1232
1252
 
1233
1253
/*
1234
 
 *  call-seq:
1235
 
 *     Thread.pass   -> nil
1236
 
 *
1237
 
 *  Invokes the thread scheduler to pass execution to another thread.
1238
 
 *
1239
 
 *     a = Thread.new { print "a"; Thread.pass;
1240
 
 *                      print "b"; Thread.pass;
1241
 
 *                      print "c" }
1242
 
 *     b = Thread.new { print "x"; Thread.pass;
1243
 
 *                      print "y"; Thread.pass;
1244
 
 *                      print "z" }
1245
 
 *     a.join
1246
 
 *     b.join
1247
 
 *
1248
 
 *  <em>produces:</em>
1249
 
 *
1250
 
 *     axbycz
 
1254
 * call-seq:
 
1255
 *    Thread.pass   -> nil
 
1256
 *
 
1257
 * Give the thread scheduler a hint to pass execution to another thread.
 
1258
 * A running thread may or may not switch, it depends on OS and processor.
1251
1259
 */
1252
1260
 
1253
1261
static VALUE
1262
1270
 */
1263
1271
 
1264
1272
static void
1265
 
rb_threadptr_execute_interrupts_rec(rb_thread_t *th, int sched_depth)
 
1273
rb_threadptr_execute_interrupts_common(rb_thread_t *th)
1266
1274
{
1267
 
    if (GET_VM()->main_thread == th) {
1268
 
        while (rb_signal_buff_size() && !th->exec_signal) native_thread_yield();
1269
 
    }
 
1275
    rb_atomic_t interrupt;
1270
1276
 
1271
1277
    if (th->raised_flag) return;
1272
1278
 
1273
 
    while (th->interrupt_flag) {
 
1279
    while ((interrupt = ATOMIC_EXCHANGE(th->interrupt_flag, 0)) != 0) {
1274
1280
        enum rb_thread_status status = th->status;
1275
 
        int timer_interrupt = th->interrupt_flag & 0x01;
1276
 
        int finalizer_interrupt = th->interrupt_flag & 0x04;
 
1281
        int timer_interrupt = interrupt & 0x01;
 
1282
        int finalizer_interrupt = interrupt & 0x04;
 
1283
        int sig;
1277
1284
 
1278
1285
        th->status = THREAD_RUNNABLE;
1279
 
        th->interrupt_flag = 0;
1280
1286
 
1281
1287
        /* signal handling */
1282
 
        if (th->exec_signal) {
1283
 
            int sig = th->exec_signal;
1284
 
            th->exec_signal = 0;
1285
 
            rb_signal_exec(th, sig);
 
1288
        if (th == th->vm->main_thread) {
 
1289
            while ((sig = rb_get_next_signal()) != 0) {
 
1290
                rb_signal_exec(th, sig);
 
1291
            }
1286
1292
        }
1287
1293
 
1288
1294
        /* exception from another thread */
1289
1295
        if (th->thrown_errinfo) {
1290
1296
            VALUE err = th->thrown_errinfo;
1291
1297
            th->thrown_errinfo = 0;
1292
 
            thread_debug("rb_thread_execute_interrupts: %ld\n", err);
 
1298
            thread_debug("rb_thread_execute_interrupts: %"PRIdVALUE"\n", err);
1293
1299
 
1294
1300
            if (err == eKillSignal || err == eTerminateSignal) {
1295
1301
                th->errinfo = INT2FIX(TAG_FATAL);
1305
1311
            rb_gc_finalize_deferred();
1306
1312
        }
1307
1313
 
1308
 
        if (!sched_depth && timer_interrupt) {
1309
 
            sched_depth++;
 
1314
        if (timer_interrupt) {
 
1315
            unsigned long limits_us = 250 * 1000;
 
1316
 
 
1317
            if (th->priority > 0)
 
1318
                limits_us <<= th->priority;
 
1319
            else
 
1320
                limits_us >>= -th->priority;
 
1321
 
 
1322
            if (status == THREAD_RUNNABLE)
 
1323
                th->running_time_us += TIME_QUANTUM_USEC;
 
1324
 
1310
1325
            EXEC_EVENT_HOOK(th, RUBY_EVENT_SWITCH, th->cfp->self, 0, 0);
1311
1326
 
1312
 
            if (th->slice > 0) {
1313
 
                th->slice--;
1314
 
            }
1315
 
            else {
1316
 
              reschedule:
1317
 
                rb_thread_schedule_rec(sched_depth+1);
1318
 
                if (th->slice < 0) {
1319
 
                    th->slice++;
1320
 
                    goto reschedule;
1321
 
                }
1322
 
                else {
1323
 
                    th->slice = th->priority;
1324
 
                }
1325
 
            }
 
1327
            rb_thread_schedule_limits(limits_us);
1326
1328
        }
1327
1329
    }
1328
1330
}
1330
1332
void
1331
1333
rb_threadptr_execute_interrupts(rb_thread_t *th)
1332
1334
{
1333
 
    rb_threadptr_execute_interrupts_rec(th, 0);
 
1335
    rb_threadptr_execute_interrupts_common(th);
 
1336
}
 
1337
 
 
1338
void
 
1339
rb_thread_execute_interrupts(VALUE thval)
 
1340
{
 
1341
    rb_thread_t *th;
 
1342
    GetThreadPtr(thval, th);
 
1343
    rb_threadptr_execute_interrupts_common(th);
1334
1344
}
1335
1345
 
1336
1346
void
1337
1347
rb_gc_mark_threads(void)
1338
1348
{
1339
 
    /* TODO: remove */
 
1349
    rb_bug("deprecated function rb_gc_mark_threads is called");
1340
1350
}
1341
1351
 
1342
1352
/*****************************************************/
1397
1407
{
1398
1408
    th->raised_flag = 0;
1399
1409
#ifdef USE_SIGALTSTACK
1400
 
    th->raised_flag = 0;
1401
1410
    rb_exc_raise(sysstack_error);
1402
1411
#else
1403
1412
    th->errinfo = sysstack_error;
1425
1434
    return 1;
1426
1435
}
1427
1436
 
 
1437
#define THREAD_IO_WAITING_P(th) (                       \
 
1438
        ((th)->status == THREAD_STOPPED ||              \
 
1439
         (th)->status == THREAD_STOPPED_FOREVER) &&     \
 
1440
        (th)->blocking_region_buffer &&                 \
 
1441
        (th)->unblock.func == ubf_select &&             \
 
1442
        1)
 
1443
 
 
1444
static int
 
1445
thread_fd_close_i(st_data_t key, st_data_t val, st_data_t data)
 
1446
{
 
1447
    int fd = (int)data;
 
1448
    rb_thread_t *th;
 
1449
    GetThreadPtr((VALUE)key, th);
 
1450
 
 
1451
    if (THREAD_IO_WAITING_P(th)) {
 
1452
        native_mutex_lock(&th->interrupt_lock);
 
1453
        if (THREAD_IO_WAITING_P(th) && th->waiting_fd == fd) {
 
1454
            th->thrown_errinfo = th->vm->special_exceptions[ruby_error_closed_stream];
 
1455
            RUBY_VM_SET_INTERRUPT(th);
 
1456
            (th->unblock.func)(th->unblock.arg);
 
1457
        }
 
1458
        native_mutex_unlock(&th->interrupt_lock);
 
1459
    }
 
1460
    return ST_CONTINUE;
 
1461
}
 
1462
 
1428
1463
void
1429
1464
rb_thread_fd_close(int fd)
1430
1465
{
1431
 
    /* TODO: fix me */
 
1466
    st_foreach(GET_THREAD()->vm->living_threads, thread_fd_close_i, (st_index_t)fd);
1432
1467
}
1433
1468
 
1434
1469
/*
1518
1553
static VALUE
1519
1554
rb_thread_s_kill(VALUE obj, VALUE th)
1520
1555
{
1521
 
    if (CLASS_OF(th) != rb_cThread) {
1522
 
        rb_raise(rb_eTypeError, 
1523
 
                "wrong argument type %s (expected Thread)",
1524
 
                rb_obj_classname(th));
1525
 
    }
1526
1556
    return rb_thread_kill(th);
1527
1557
}
1528
1558
 
1552
1582
 *  I/O, however). Does not invoke the scheduler (see <code>Thread#run</code>).
1553
1583
 *
1554
1584
 *     c = Thread.new { Thread.stop; puts "hey!" }
 
1585
 *     sleep 0.1 while c.status!='sleep'
1555
1586
 *     c.wakeup
 
1587
 *     c.join
1556
1588
 *
1557
1589
 *  <em>produces:</em>
1558
1590
 *
1562
1594
VALUE
1563
1595
rb_thread_wakeup(VALUE thread)
1564
1596
{
 
1597
    if (!RTEST(rb_thread_wakeup_alive(thread))) {
 
1598
        rb_raise(rb_eThreadError, "killed thread");
 
1599
    }
 
1600
    return thread;
 
1601
}
 
1602
 
 
1603
VALUE
 
1604
rb_thread_wakeup_alive(VALUE thread)
 
1605
{
1565
1606
    rb_thread_t *th;
1566
1607
    GetThreadPtr(thread, th);
1567
1608
 
1568
1609
    if (th->status == THREAD_KILLED) {
1569
 
        rb_raise(rb_eThreadError, "killed thread");
 
1610
        return Qnil;
1570
1611
    }
1571
1612
    rb_threadptr_ready(th);
1572
1613
    if (th->status != THREAD_TO_KILL) {
1583
1624
 *  Wakes up <i>thr</i>, making it eligible for scheduling.
1584
1625
 *
1585
1626
 *     a = Thread.new { puts "a"; Thread.stop; puts "c" }
1586
 
 *     Thread.pass
 
1627
 *     sleep 0.1 while a.status!='sleep'
1587
1628
 *     puts "Got here"
1588
1629
 *     a.run
1589
1630
 *     a.join
1612
1653
 *  and schedules execution of another thread.
1613
1654
 *
1614
1655
 *     a = Thread.new { print "a"; Thread.stop; print "c" }
1615
 
 *     Thread.pass
 
1656
 *     sleep 0.1 while a.status!='sleep'
1616
1657
 *     print "b"
1617
1658
 *     a.run
1618
1659
 *     a.join
1998
2039
rb_thread_local_aref(VALUE thread, ID id)
1999
2040
{
2000
2041
    rb_thread_t *th;
2001
 
    VALUE val;
 
2042
    st_data_t val;
2002
2043
 
2003
2044
    GetThreadPtr(thread, th);
2004
2045
    if (rb_safe_level() >= 4 && th != GET_THREAD()) {
2008
2049
        return Qnil;
2009
2050
    }
2010
2051
    if (st_lookup(th->local_storage, id, &val)) {
2011
 
        return val;
 
2052
        return (VALUE)val;
2012
2053
    }
2013
2054
    return Qnil;
2014
2055
}
2021
2062
 *  either a symbol or a string name. If the specified variable does not exist,
2022
2063
 *  returns <code>nil</code>.
2023
2064
 *
2024
 
 *     a = Thread.new { Thread.current["name"] = "A"; Thread.stop }
2025
 
 *     b = Thread.new { Thread.current[:name]  = "B"; Thread.stop }
2026
 
 *     c = Thread.new { Thread.current["name"] = "C"; Thread.stop }
2027
 
 *     Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" }
 
2065
 *     [
 
2066
 *       Thread.new { Thread.current["name"] = "A" },
 
2067
 *       Thread.new { Thread.current[:name]  = "B" },
 
2068
 *       Thread.new { Thread.current["name"] = "C" }
 
2069
 *     ].each do |th|
 
2070
 *       th.join
 
2071
 *       puts "#{th.inspect}: #{th[:name]}"
 
2072
 *     end
2028
2073
 *
2029
2074
 *  <em>produces:</em>
2030
2075
 *
2031
 
 *     #<Thread:0x401b3b3c sleep>: C
2032
 
 *     #<Thread:0x401b3bc8 sleep>: B
2033
 
 *     #<Thread:0x401b3c68 sleep>: A
2034
 
 *     #<Thread:0x401bdf4c run>:
 
2076
 *     #<Thread:0x00000002a54220 dead>: A
 
2077
 *     #<Thread:0x00000002a541a8 dead>: B
 
2078
 *     #<Thread:0x00000002a54130 dead>: C
2035
2079
 */
2036
2080
 
2037
2081
static VALUE
2229
2273
        priority = RUBY_THREAD_PRIORITY_MIN;
2230
2274
    }
2231
2275
    th->priority = priority;
2232
 
    th->slice = priority;
2233
2276
#endif
2234
2277
    return INT2NUM(th->priority);
2235
2278
}
2266
2309
 */
2267
2310
 
2268
2311
void
2269
 
rb_fd_init(volatile rb_fdset_t *fds)
 
2312
rb_fd_init(rb_fdset_t *fds)
2270
2313
{
2271
2314
    fds->maxfd = 0;
2272
2315
    fds->fdset = ALLOC(fd_set);
2274
2317
}
2275
2318
 
2276
2319
void
 
2320
rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
 
2321
{
 
2322
    size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
 
2323
 
 
2324
    if (size < sizeof(fd_set))
 
2325
        size = sizeof(fd_set);
 
2326
    dst->maxfd = src->maxfd;
 
2327
    dst->fdset = xmalloc(size);
 
2328
    memcpy(dst->fdset, src->fdset, size);
 
2329
}
 
2330
 
 
2331
void
2277
2332
rb_fd_term(rb_fdset_t *fds)
2278
2333
{
2279
2334
    if (fds->fdset) xfree(fds->fdset);
2284
2339
void
2285
2340
rb_fd_zero(rb_fdset_t *fds)
2286
2341
{
2287
 
    if (fds->fdset) {
 
2342
    if (fds->fdset)
2288
2343
        MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
2289
 
        FD_ZERO(fds->fdset);
2290
 
    }
2291
2344
}
2292
2345
 
2293
2346
static void
2338
2391
    memcpy(dst->fdset, src, size);
2339
2392
}
2340
2393
 
 
2394
static void
 
2395
rb_fd_rcopy(fd_set *dst, rb_fdset_t *src)
 
2396
{
 
2397
    size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
 
2398
 
 
2399
    if (size > sizeof(fd_set)) {
 
2400
        rb_raise(rb_eArgError, "too large fdsets");
 
2401
    }
 
2402
    memcpy(dst, rb_fd_ptr(src), sizeof(fd_set));
 
2403
}
 
2404
 
 
2405
void
 
2406
rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
 
2407
{
 
2408
    size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
 
2409
 
 
2410
    if (size < sizeof(fd_set))
 
2411
        size = sizeof(fd_set);
 
2412
    dst->maxfd = src->maxfd;
 
2413
    dst->fdset = xrealloc(dst->fdset, size);
 
2414
    memcpy(dst->fdset, src->fdset, size);
 
2415
}
 
2416
 
2341
2417
int
2342
2418
rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout)
2343
2419
{
2363
2439
#undef FD_ISSET
2364
2440
 
2365
2441
#define FD_ZERO(f)      rb_fd_zero(f)
2366
 
#define FD_SET(i, f)    rb_fd_set(i, f)
2367
 
#define FD_CLR(i, f)    rb_fd_clr(i, f)
2368
 
#define FD_ISSET(i, f)  rb_fd_isset(i, f)
 
2442
#define FD_SET(i, f)    rb_fd_set((i), (f))
 
2443
#define FD_CLR(i, f)    rb_fd_clr((i), (f))
 
2444
#define FD_ISSET(i, f)  rb_fd_isset((i), (f))
2369
2445
 
2370
2446
#elif defined(_WIN32)
2371
2447
 
2372
2448
void
2373
 
rb_fd_init(volatile rb_fdset_t *set)
 
2449
rb_fd_init(rb_fdset_t *set)
2374
2450
{
2375
2451
    set->capa = FD_SETSIZE;
2376
2452
    set->fdset = ALLOC(fd_set);
2378
2454
}
2379
2455
 
2380
2456
void
 
2457
rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
 
2458
{
 
2459
    rb_fd_init(dst);
 
2460
    rb_fd_dup(dst, src);
 
2461
}
 
2462
 
 
2463
static void
 
2464
rb_fd_rcopy(fd_set *dst, rb_fdset_t *src)
 
2465
{
 
2466
    int max = rb_fd_max(src);
 
2467
 
 
2468
    /* we assume src is the result of select() with dst, so dst should be
 
2469
     * larger or equal than src. */
 
2470
    if (max > FD_SETSIZE || max > dst->fd_count) {
 
2471
        rb_raise(rb_eArgError, "too large fdsets");
 
2472
    }
 
2473
 
 
2474
    memcpy(dst->fd_array, src->fdset->fd_array, max);
 
2475
    dst->fd_count = max;
 
2476
}
 
2477
 
 
2478
void
2381
2479
rb_fd_term(rb_fdset_t *set)
2382
2480
{
2383
2481
    xfree(set->fdset);
2409
2507
#undef FD_ISSET
2410
2508
 
2411
2509
#define FD_ZERO(f)      rb_fd_zero(f)
2412
 
#define FD_SET(i, f)    rb_fd_set(i, f)
2413
 
#define FD_CLR(i, f)    rb_fd_clr(i, f)
2414
 
#define FD_ISSET(i, f)  rb_fd_isset(i, f)
 
2510
#define FD_SET(i, f)    rb_fd_set((i), (f))
 
2511
#define FD_CLR(i, f)    rb_fd_clr((i), (f))
 
2512
#define FD_ISSET(i, f)  rb_fd_isset((i), (f))
2415
2513
 
 
2514
#else
 
2515
#define rb_fd_rcopy(d, s) (*(d) = *(s))
2416
2516
#endif
2417
2517
 
2418
 
#if defined(__CYGWIN__) || defined(_WIN32)
 
2518
#if defined(__CYGWIN__)
2419
2519
static long
2420
2520
cmp_tv(const struct timeval *a, const struct timeval *b)
2421
2521
{
2443
2543
#endif
2444
2544
 
2445
2545
static int
2446
 
do_select(int n, fd_set *read, fd_set *write, fd_set *except,
 
2546
do_select(int n, rb_fdset_t *read, rb_fdset_t *write, rb_fdset_t *except,
2447
2547
          struct timeval *timeout)
2448
2548
{
2449
2549
    int result, lerrno;
2450
 
    fd_set UNINITIALIZED_VAR(orig_read);
2451
 
    fd_set UNINITIALIZED_VAR(orig_write);
2452
 
    fd_set UNINITIALIZED_VAR(orig_except);
2453
 
 
2454
 
#ifndef linux
 
2550
    rb_fdset_t UNINITIALIZED_VAR(orig_read);
 
2551
    rb_fdset_t UNINITIALIZED_VAR(orig_write);
 
2552
    rb_fdset_t UNINITIALIZED_VAR(orig_except);
2455
2553
    double limit = 0;
2456
2554
    struct timeval wait_rest;
2457
 
# if defined(__CYGWIN__) || defined(_WIN32)
 
2555
# if defined(__CYGWIN__)
2458
2556
    struct timeval start_time;
2459
2557
# endif
2460
2558
 
2461
2559
    if (timeout) {
2462
 
# if defined(__CYGWIN__) || defined(_WIN32)
 
2560
# if defined(__CYGWIN__)
2463
2561
        gettimeofday(&start_time, NULL);
2464
2562
        limit = (double)start_time.tv_sec + (double)start_time.tv_usec*1e-6;
2465
2563
# else
2469
2567
        wait_rest = *timeout;
2470
2568
        timeout = &wait_rest;
2471
2569
    }
2472
 
#endif
2473
2570
 
2474
 
    if (read) orig_read = *read;
2475
 
    if (write) orig_write = *write;
2476
 
    if (except) orig_except = *except;
 
2571
    if (read)
 
2572
        rb_fd_init_copy(&orig_read, read);
 
2573
    if (write)
 
2574
        rb_fd_init_copy(&orig_write, write);
 
2575
    if (except)
 
2576
        rb_fd_init_copy(&orig_except, except);
2477
2577
 
2478
2578
  retry:
2479
2579
    lerrno = 0;
2480
2580
 
2481
 
#if defined(__CYGWIN__) || defined(_WIN32)
 
2581
#if defined(__CYGWIN__)
2482
2582
    {
2483
2583
        int finish = 0;
2484
2584
        /* polling duration: 100ms */
2490
2590
            wait = (timeout == 0 || cmp_tv(&wait_100ms, timeout) < 0) ? &wait_100ms : timeout;
2491
2591
            BLOCKING_REGION({
2492
2592
                do {
2493
 
                    result = select(n, read, write, except, wait);
 
2593
                    result = rb_fd_select(n, read, write, except, wait);
2494
2594
                    if (result < 0) lerrno = errno;
2495
2595
                    if (result != 0) break;
2496
2596
 
2497
 
                    if (read) *read = orig_read;
2498
 
                    if (write) *write = orig_write;
2499
 
                    if (except) *except = orig_except;
 
2597
                    if (read)
 
2598
                        rb_fd_dup(read, &orig_read);
 
2599
                    if (write)
 
2600
                        rb_fd_dup(write, &orig_write);
 
2601
                    if (except)
 
2602
                        rb_fd_dup(except, &orig_except);
2500
2603
                    if (timeout) {
2501
2604
                        struct timeval elapsed;
2502
2605
                        gettimeofday(&elapsed, NULL);
2512
2615
            }, 0, 0);
2513
2616
        } while (result == 0 && !finish);
2514
2617
    }
 
2618
#elif defined(_WIN32)
 
2619
    {
 
2620
        rb_thread_t *th = GET_THREAD();
 
2621
        BLOCKING_REGION({
 
2622
            result = native_fd_select(n, read, write, except, timeout, th);
 
2623
            if (result < 0) lerrno = errno;
 
2624
        }, ubf_select, th);
 
2625
    }
2515
2626
#else
2516
2627
    BLOCKING_REGION({
2517
 
        result = select(n, read, write, except, timeout);
 
2628
        result = rb_fd_select(n, read, write, except, timeout);
2518
2629
        if (result < 0) lerrno = errno;
2519
2630
    }, ubf_select, GET_THREAD());
2520
2631
#endif
2527
2638
#ifdef ERESTART
2528
2639
          case ERESTART:
2529
2640
#endif
2530
 
            if (read) *read = orig_read;
2531
 
            if (write) *write = orig_write;
2532
 
            if (except) *except = orig_except;
2533
 
#ifndef linux
 
2641
            if (read)
 
2642
                rb_fd_dup(read, &orig_read);
 
2643
            if (write)
 
2644
                rb_fd_dup(write, &orig_write);
 
2645
            if (except)
 
2646
                rb_fd_dup(except, &orig_except);
 
2647
 
2534
2648
            if (timeout) {
2535
2649
                double d = limit - timeofday();
2536
2650
 
2539
2653
                if (wait_rest.tv_sec < 0)  wait_rest.tv_sec = 0;
2540
2654
                if (wait_rest.tv_usec < 0) wait_rest.tv_usec = 0;
2541
2655
            }
2542
 
#endif
 
2656
 
2543
2657
            goto retry;
2544
2658
          default:
2545
2659
            break;
2546
2660
        }
2547
2661
    }
 
2662
 
 
2663
    if (read)
 
2664
        rb_fd_term(&orig_read);
 
2665
    if (write)
 
2666
        rb_fd_term(&orig_write);
 
2667
    if (except)
 
2668
        rb_fd_term(&orig_except);
 
2669
 
2548
2670
    return result;
2549
2671
}
2550
2672
 
2552
2674
rb_thread_wait_fd_rw(int fd, int read)
2553
2675
{
2554
2676
    int result = 0;
 
2677
    int events = read ? RB_WAITFD_IN : RB_WAITFD_OUT;
 
2678
 
2555
2679
    thread_debug("rb_thread_wait_fd_rw(%d, %s)\n", fd, read ? "read" : "write");
2556
2680
 
2557
2681
    if (fd < 0) {
2559
2683
    }
2560
2684
    if (rb_thread_alone()) return;
2561
2685
    while (result <= 0) {
2562
 
        rb_fdset_t set;
2563
 
        rb_fd_init(&set);
2564
 
        FD_SET(fd, &set);
2565
 
 
2566
 
        if (read) {
2567
 
            result = do_select(fd + 1, rb_fd_ptr(&set), 0, 0, 0);
2568
 
        }
2569
 
        else {
2570
 
            result = do_select(fd + 1, 0, rb_fd_ptr(&set), 0, 0);
2571
 
        }
2572
 
 
2573
 
        rb_fd_term(&set);
 
2686
        result = rb_wait_for_single_fd(fd, events, NULL);
2574
2687
 
2575
2688
        if (result < 0) {
2576
2689
            rb_sys_fail(0);
2597
2710
rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except,
2598
2711
                 struct timeval *timeout)
2599
2712
{
2600
 
    if (!read && !write && !except) {
2601
 
        if (!timeout) {
2602
 
            rb_thread_sleep_forever();
2603
 
            return 0;
2604
 
        }
2605
 
        rb_thread_wait_for(*timeout);
2606
 
        return 0;
2607
 
    }
2608
 
    else {
2609
 
        return do_select(max, read, write, except, timeout);
2610
 
    }
 
2713
    rb_fdset_t fdsets[3];
 
2714
    rb_fdset_t *rfds = NULL;
 
2715
    rb_fdset_t *wfds = NULL;
 
2716
    rb_fdset_t *efds = NULL;
 
2717
    int retval;
 
2718
 
 
2719
    if (read) {
 
2720
        rfds = &fdsets[0];
 
2721
        rb_fd_init(rfds);
 
2722
        rb_fd_copy(rfds, read, max);
 
2723
    }
 
2724
    if (write) {
 
2725
        wfds = &fdsets[1];
 
2726
        rb_fd_init(wfds);
 
2727
        rb_fd_copy(wfds, write, max);
 
2728
    }
 
2729
    if (except) {
 
2730
        efds = &fdsets[2];
 
2731
        rb_fd_init(efds);
 
2732
        rb_fd_copy(efds, except, max);
 
2733
    }
 
2734
 
 
2735
    retval = rb_thread_fd_select(max, rfds, wfds, efds, timeout);
 
2736
 
 
2737
    if (rfds) {
 
2738
        rb_fd_rcopy(read, rfds);
 
2739
        rb_fd_term(rfds);
 
2740
    }
 
2741
    if (wfds) {
 
2742
        rb_fd_rcopy(write, wfds);
 
2743
        rb_fd_term(wfds);
 
2744
    }
 
2745
    if (efds) {
 
2746
        rb_fd_rcopy(except, efds);
 
2747
        rb_fd_term(efds);
 
2748
    }
 
2749
 
 
2750
    return retval;
2611
2751
}
2612
2752
 
2613
 
 
2614
2753
int
2615
2754
rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t * except,
2616
2755
                    struct timeval *timeout)
2617
2756
{
2618
 
    fd_set *r = NULL, *w = NULL, *e = NULL;
2619
 
 
2620
2757
    if (!read && !write && !except) {
2621
2758
        if (!timeout) {
2622
2759
            rb_thread_sleep_forever();
2627
2764
    }
2628
2765
 
2629
2766
    if (read) {
2630
 
        rb_fd_resize(max - 1, read);
2631
 
        r = rb_fd_ptr(read);
 
2767
        rb_fd_resize(max - 1, read);
2632
2768
    }
2633
2769
    if (write) {
2634
 
        rb_fd_resize(max - 1, write);
2635
 
        w = rb_fd_ptr(write);
 
2770
        rb_fd_resize(max - 1, write);
2636
2771
    }
2637
2772
    if (except) {
2638
 
        rb_fd_resize(max - 1, except);
2639
 
        e = rb_fd_ptr(except);
2640
 
    }
2641
 
    return do_select(max, r, w, e, timeout);
2642
 
}
2643
 
 
 
2773
        rb_fd_resize(max - 1, except);
 
2774
    }
 
2775
    return do_select(max, read, write, except, timeout);
 
2776
}
 
2777
 
 
2778
/*
 
2779
 * poll() is supported by many OSes, but so far Linux is the only
 
2780
 * one we know of that supports using poll() in all places select()
 
2781
 * would work.
 
2782
 */
 
2783
#if defined(HAVE_POLL) && defined(linux)
 
2784
#  define USE_POLL
 
2785
#endif
 
2786
 
 
2787
#ifdef USE_POLL
 
2788
 
 
2789
/* The same with linux kernel. TODO: make platform independent definition. */
 
2790
#define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
 
2791
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
 
2792
#define POLLEX_SET (POLLPRI)
 
2793
 
 
2794
#define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0))
 
2795
#define TIMET_MIN (~(time_t)0 <= 0 ? (time_t)(((unsigned_time_t)1) << (sizeof(time_t) * CHAR_BIT - 1)) : (time_t)0)
 
2796
 
 
2797
#ifndef HAVE_PPOLL
 
2798
/* TODO: don't ignore sigmask */
 
2799
int ppoll(struct pollfd *fds, nfds_t nfds,
 
2800
          const struct timespec *ts, const sigset_t *sigmask)
 
2801
{
 
2802
    int timeout_ms;
 
2803
 
 
2804
    if (ts) {
 
2805
        int tmp, tmp2;
 
2806
 
 
2807
        if (ts->tv_sec > TIMET_MAX/1000)
 
2808
            timeout_ms = -1;
 
2809
        else {
 
2810
            tmp = ts->tv_sec * 1000;
 
2811
            tmp2 = ts->tv_nsec / (1000 * 1000);
 
2812
            if (TIMET_MAX - tmp < tmp2)
 
2813
                timeout_ms = -1;
 
2814
            else
 
2815
                timeout_ms = tmp + tmp2;
 
2816
        }
 
2817
    } else
 
2818
        timeout_ms = -1;
 
2819
 
 
2820
    return poll(fds, nfds, timeout_ms);
 
2821
}
 
2822
#endif
 
2823
 
 
2824
/*
 
2825
 * returns a mask of events
 
2826
 */
 
2827
int
 
2828
rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
 
2829
{
 
2830
    struct pollfd fds;
 
2831
    int result, lerrno;
 
2832
    double limit = 0;
 
2833
    struct timespec ts;
 
2834
    struct timespec *timeout = NULL;
 
2835
 
 
2836
    if (tv) {
 
2837
        ts.tv_sec = tv->tv_sec;
 
2838
        ts.tv_nsec = tv->tv_usec * 1000;
 
2839
        limit = timeofday();
 
2840
        limit += (double)tv->tv_sec + (double)tv->tv_usec * 1e-6;
 
2841
        timeout = &ts;
 
2842
    }
 
2843
 
 
2844
    fds.fd = fd;
 
2845
    fds.events = (short)events;
 
2846
 
 
2847
retry:
 
2848
    lerrno = 0;
 
2849
    BLOCKING_REGION({
 
2850
        result = ppoll(&fds, 1, timeout, NULL);
 
2851
        if (result < 0) lerrno = errno;
 
2852
    }, ubf_select, GET_THREAD());
 
2853
 
 
2854
    if (result < 0) {
 
2855
        errno = lerrno;
 
2856
        switch (errno) {
 
2857
          case EINTR:
 
2858
#ifdef ERESTART
 
2859
          case ERESTART:
 
2860
#endif
 
2861
            if (timeout) {
 
2862
                double d = limit - timeofday();
 
2863
 
 
2864
                ts.tv_sec = (long)d;
 
2865
                ts.tv_nsec = (long)((d - (double)ts.tv_sec) * 1e9);
 
2866
                if (ts.tv_sec < 0)
 
2867
                    ts.tv_sec = 0;
 
2868
                if (ts.tv_nsec < 0)
 
2869
                    ts.tv_nsec = 0;
 
2870
            }
 
2871
            goto retry;
 
2872
        }
 
2873
        return -1;
 
2874
    }
 
2875
 
 
2876
    if (fds.revents & POLLNVAL) {
 
2877
        errno = EBADF;
 
2878
        return -1;
 
2879
    }
 
2880
 
 
2881
    /*
 
2882
     * POLLIN, POLLOUT have a different meanings from select(2)'s read/write bit.
 
2883
     * Therefore we need fix it up.
 
2884
     */
 
2885
    result = 0;
 
2886
    if (fds.revents & POLLIN_SET)
 
2887
        result |= RB_WAITFD_IN;
 
2888
    if (fds.revents & POLLOUT_SET)
 
2889
        result |= RB_WAITFD_OUT;
 
2890
    if (fds.revents & POLLEX_SET)
 
2891
        result |= RB_WAITFD_PRI;
 
2892
 
 
2893
    return result;
 
2894
}
 
2895
#else /* ! USE_POLL - implement rb_io_poll_fd() using select() */
 
2896
static rb_fdset_t *init_set_fd(int fd, rb_fdset_t *fds)
 
2897
{
 
2898
    rb_fd_init(fds);
 
2899
    rb_fd_set(fd, fds);
 
2900
 
 
2901
    return fds;
 
2902
}
 
2903
 
 
2904
struct select_args {
 
2905
    union {
 
2906
        int fd;
 
2907
        int error;
 
2908
    } as;
 
2909
    rb_fdset_t *read;
 
2910
    rb_fdset_t *write;
 
2911
    rb_fdset_t *except;
 
2912
    struct timeval *tv;
 
2913
};
 
2914
 
 
2915
static VALUE
 
2916
select_single(VALUE ptr)
 
2917
{
 
2918
    struct select_args *args = (struct select_args *)ptr;
 
2919
    int r;
 
2920
 
 
2921
    r = rb_thread_fd_select(args->as.fd + 1,
 
2922
                            args->read, args->write, args->except, args->tv);
 
2923
    if (r == -1)
 
2924
        args->as.error = errno;
 
2925
    if (r > 0) {
 
2926
        r = 0;
 
2927
        if (args->read && rb_fd_isset(args->as.fd, args->read))
 
2928
            r |= RB_WAITFD_IN;
 
2929
        if (args->write && rb_fd_isset(args->as.fd, args->write))
 
2930
            r |= RB_WAITFD_OUT;
 
2931
        if (args->except && rb_fd_isset(args->as.fd, args->except))
 
2932
            r |= RB_WAITFD_PRI;
 
2933
    }
 
2934
    return (VALUE)r;
 
2935
}
 
2936
 
 
2937
static VALUE
 
2938
select_single_cleanup(VALUE ptr)
 
2939
{
 
2940
    struct select_args *args = (struct select_args *)ptr;
 
2941
 
 
2942
    if (args->read) rb_fd_term(args->read);
 
2943
    if (args->write) rb_fd_term(args->write);
 
2944
    if (args->except) rb_fd_term(args->except);
 
2945
 
 
2946
    return (VALUE)-1;
 
2947
}
 
2948
 
 
2949
int
 
2950
rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
 
2951
{
 
2952
    rb_fdset_t rfds, wfds, efds;
 
2953
    struct select_args args;
 
2954
    int r;
 
2955
    VALUE ptr = (VALUE)&args;
 
2956
 
 
2957
    args.as.fd = fd;
 
2958
    args.read = (events & RB_WAITFD_IN) ? init_set_fd(fd, &rfds) : NULL;
 
2959
    args.write = (events & RB_WAITFD_OUT) ? init_set_fd(fd, &wfds) : NULL;
 
2960
    args.except = (events & RB_WAITFD_PRI) ? init_set_fd(fd, &efds) : NULL;
 
2961
    args.tv = tv;
 
2962
 
 
2963
    r = (int)rb_ensure(select_single, ptr, select_single_cleanup, ptr);
 
2964
    if (r == -1)
 
2965
        errno = args.as.error;
 
2966
 
 
2967
    return r;
 
2968
}
 
2969
#endif /* ! USE_POLL */
2644
2970
 
2645
2971
/*
2646
2972
 * for GC
2669
2995
 *
2670
2996
 */
2671
2997
 
2672
 
int rb_get_next_signal(void);
2673
 
 
2674
2998
void
2675
2999
rb_threadptr_check_signal(rb_thread_t *mth)
2676
3000
{
2677
 
    int sig;
2678
 
 
2679
3001
    /* mth must be main_thread */
2680
 
 
2681
 
    if (!mth->exec_signal && (sig = rb_get_next_signal()) > 0) {
2682
 
        enum rb_thread_status prev_status = mth->status;
2683
 
        thread_debug("main_thread: %s, sig: %d\n",
2684
 
                     thread_status_name(prev_status), sig);
2685
 
        mth->exec_signal = sig;
2686
 
        if (mth->status != THREAD_KILLED) mth->status = THREAD_RUNNABLE;
 
3002
    if (rb_signal_buff_size() > 0) {
 
3003
        /* wakeup main thread */
2687
3004
        rb_threadptr_interrupt(mth);
2688
 
        mth->status = prev_status;
2689
3005
    }
2690
3006
}
2691
3007
 
2713
3029
}
2714
3030
 
2715
3031
void
2716
 
rb_thread_stop_timer_thread(void)
 
3032
rb_thread_stop_timer_thread(int close_anyway)
2717
3033
{
2718
 
    if (timer_thread_id && native_stop_timer_thread()) {
 
3034
    if (timer_thread_id && native_stop_timer_thread(close_anyway)) {
2719
3035
        native_reset_timer_thread();
2720
3036
    }
2721
3037
}
2750
3066
static void
2751
3067
clear_coverage(void)
2752
3068
{
2753
 
    extern VALUE rb_get_coverages(void);
2754
3069
    VALUE coverages = rb_get_coverages();
2755
3070
    if (RTEST(coverages)) {
2756
3071
        st_foreach(RHASH_TBL(coverages), clear_coverage_i, 0);
2765
3080
    VALUE thval = th->self;
2766
3081
    vm->main_thread = th;
2767
3082
 
2768
 
    native_mutex_reinitialize_atfork(&th->vm->global_vm_lock);
 
3083
    gvl_atfork(th->vm);
2769
3084
    st_foreach(vm->living_threads, atfork, (st_data_t)th);
2770
3085
    st_clear(vm->living_threads);
2771
3086
    st_insert(vm->living_threads, thval, (st_data_t)th->thread_id);
2795
3110
{
2796
3111
    rb_thread_atfork_internal(terminate_atfork_i);
2797
3112
    GET_THREAD()->join_list_head = 0;
 
3113
 
 
3114
    /* We don't want reproduce CVE-2003-0900. */
2798
3115
    rb_reset_random_seed();
2799
3116
}
2800
3117
 
2830
3147
 
2831
3148
static const rb_data_type_t thgroup_data_type = {
2832
3149
    "thgroup",
2833
 
    NULL, RUBY_TYPED_DEFAULT_FREE, thgroup_memsize,
 
3150
    {NULL, RUBY_TYPED_DEFAULT_FREE, thgroup_memsize,},
2834
3151
};
2835
3152
 
2836
3153
/*
3038
3355
 */
3039
3356
 
3040
3357
#define GetMutexPtr(obj, tobj) \
3041
 
    TypedData_Get_Struct(obj, mutex_t, &mutex_data_type, tobj)
 
3358
    TypedData_Get_Struct((obj), rb_mutex_t, &mutex_data_type, (tobj))
3042
3359
 
3043
 
static const char *mutex_unlock(mutex_t *mutex, rb_thread_t volatile *th);
 
3360
static const char *rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th);
3044
3361
 
3045
3362
#define mutex_mark NULL
3046
3363
 
3048
3365
mutex_free(void *ptr)
3049
3366
{
3050
3367
    if (ptr) {
3051
 
        mutex_t *mutex = ptr;
 
3368
        rb_mutex_t *mutex = ptr;
3052
3369
        if (mutex->th) {
3053
3370
            /* rb_warn("free locked mutex"); */
3054
 
            const char *err = mutex_unlock(mutex, mutex->th);
 
3371
            const char *err = rb_mutex_unlock_th(mutex, mutex->th);
3055
3372
            if (err) rb_bug("%s", err);
3056
3373
        }
3057
3374
        native_mutex_destroy(&mutex->lock);
3063
3380
static size_t
3064
3381
mutex_memsize(const void *ptr)
3065
3382
{
3066
 
    return ptr ? sizeof(mutex_t) : 0;
 
3383
    return ptr ? sizeof(rb_mutex_t) : 0;
3067
3384
}
3068
3385
 
3069
3386
static const rb_data_type_t mutex_data_type = {
3070
3387
    "mutex",
3071
 
    mutex_mark, mutex_free, mutex_memsize,
 
3388
    {mutex_mark, mutex_free, mutex_memsize,},
3072
3389
};
3073
3390
 
 
3391
VALUE
 
3392
rb_obj_is_mutex(VALUE obj)
 
3393
{
 
3394
    if (rb_typeddata_is_kind_of(obj, &mutex_data_type)) {
 
3395
        return Qtrue;
 
3396
    }
 
3397
    else {
 
3398
        return Qfalse;
 
3399
    }
 
3400
}
 
3401
 
3074
3402
static VALUE
3075
3403
mutex_alloc(VALUE klass)
3076
3404
{
3077
3405
    VALUE volatile obj;
3078
 
    mutex_t *mutex;
 
3406
    rb_mutex_t *mutex;
3079
3407
 
3080
 
    obj = TypedData_Make_Struct(klass, mutex_t, &mutex_data_type, mutex);
 
3408
    obj = TypedData_Make_Struct(klass, rb_mutex_t, &mutex_data_type, mutex);
3081
3409
    native_mutex_initialize(&mutex->lock);
3082
 
    native_cond_initialize(&mutex->cond);
 
3410
    native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC);
3083
3411
    return obj;
3084
3412
}
3085
3413
 
3110
3438
VALUE
3111
3439
rb_mutex_locked_p(VALUE self)
3112
3440
{
3113
 
    mutex_t *mutex;
 
3441
    rb_mutex_t *mutex;
3114
3442
    GetMutexPtr(self, mutex);
3115
3443
    return mutex->th ? Qtrue : Qfalse;
3116
3444
}
3118
3446
static void
3119
3447
mutex_locked(rb_thread_t *th, VALUE self)
3120
3448
{
3121
 
    mutex_t *mutex;
 
3449
    rb_mutex_t *mutex;
3122
3450
    GetMutexPtr(self, mutex);
3123
3451
 
3124
3452
    if (th->keeping_mutexes) {
3137
3465
VALUE
3138
3466
rb_mutex_trylock(VALUE self)
3139
3467
{
3140
 
    mutex_t *mutex;
 
3468
    rb_mutex_t *mutex;
3141
3469
    VALUE locked = Qfalse;
3142
3470
    GetMutexPtr(self, mutex);
3143
3471
 
3154
3482
}
3155
3483
 
3156
3484
static int
3157
 
lock_func(rb_thread_t *th, mutex_t *mutex, int last_thread)
 
3485
lock_func(rb_thread_t *th, rb_mutex_t *mutex, int timeout_ms)
3158
3486
{
3159
3487
    int interrupted = 0;
3160
 
#if 0 /* for debug */
3161
 
    native_thread_yield();
3162
 
#endif
 
3488
    int err = 0;
3163
3489
 
3164
 
    native_mutex_lock(&mutex->lock);
3165
 
    th->transition_for_lock = 0;
3166
 
    while (mutex->th || (mutex->th = th, 0)) {
3167
 
        if (last_thread) {
3168
 
            interrupted = 2;
 
3490
    mutex->cond_waiting++;
 
3491
    for (;;) {
 
3492
        if (!mutex->th) {
 
3493
            mutex->th = th;
3169
3494
            break;
3170
3495
        }
3171
 
 
3172
 
        mutex->cond_waiting++;
3173
 
        native_cond_wait(&mutex->cond, &mutex->lock);
3174
 
        mutex->cond_notified--;
3175
 
 
3176
3496
        if (RUBY_VM_INTERRUPTED(th)) {
3177
3497
            interrupted = 1;
3178
3498
            break;
3179
3499
        }
 
3500
        if (err == ETIMEDOUT) {
 
3501
            interrupted = 2;
 
3502
            break;
 
3503
        }
 
3504
 
 
3505
        if (timeout_ms) {
 
3506
            struct timespec timeout_rel;
 
3507
            struct timespec timeout;
 
3508
 
 
3509
            timeout_rel.tv_sec = 0;
 
3510
            timeout_rel.tv_nsec = timeout_ms * 1000 * 1000;
 
3511
            timeout = native_cond_timeout(&mutex->cond, timeout_rel);
 
3512
            err = native_cond_timedwait(&mutex->cond, &mutex->lock, &timeout);
 
3513
        }
 
3514
        else {
 
3515
            native_cond_wait(&mutex->cond, &mutex->lock);
 
3516
            err = 0;
 
3517
        }
3180
3518
    }
3181
 
    th->transition_for_lock = 1;
3182
 
    native_mutex_unlock(&mutex->lock);
3183
 
 
3184
 
    if (interrupted == 2) native_thread_yield();
3185
 
#if 0 /* for debug */
3186
 
    native_thread_yield();
3187
 
#endif
 
3519
    mutex->cond_waiting--;
3188
3520
 
3189
3521
    return interrupted;
3190
3522
}
3192
3524
static void
3193
3525
lock_interrupt(void *ptr)
3194
3526
{
3195
 
    mutex_t *mutex = (mutex_t *)ptr;
 
3527
    rb_mutex_t *mutex = (rb_mutex_t *)ptr;
3196
3528
    native_mutex_lock(&mutex->lock);
3197
 
    if (mutex->cond_waiting > 0) {
 
3529
    if (mutex->cond_waiting > 0)
3198
3530
        native_cond_broadcast(&mutex->cond);
3199
 
        mutex->cond_notified = mutex->cond_waiting;
3200
 
        mutex->cond_waiting = 0;
3201
 
    }
3202
3531
    native_mutex_unlock(&mutex->lock);
3203
3532
}
3204
3533
 
3214
3543
{
3215
3544
 
3216
3545
    if (rb_mutex_trylock(self) == Qfalse) {
3217
 
        mutex_t *mutex;
 
3546
        rb_mutex_t *mutex;
3218
3547
        rb_thread_t *th = GET_THREAD();
3219
3548
        GetMutexPtr(self, mutex);
3220
3549
 
3225
3554
        while (mutex->th != th) {
3226
3555
            int interrupted;
3227
3556
            enum rb_thread_status prev_status = th->status;
3228
 
            int last_thread = 0;
 
3557
            int timeout_ms = 0;
3229
3558
            struct rb_unblock_callback oldubf;
3230
3559
 
3231
3560
            set_unblock_function(th, lock_interrupt, mutex, &oldubf);
3232
3561
            th->status = THREAD_STOPPED_FOREVER;
3233
 
            th->vm->sleeper++;
3234
3562
            th->locking_mutex = self;
 
3563
 
 
3564
            native_mutex_lock(&mutex->lock);
 
3565
            th->vm->sleeper++;
 
3566
            /*
 
3567
             * Carefully! while some contended threads are in lock_func(),
 
3568
             * vm->sleepr is unstable value. we have to avoid both deadlock
 
3569
             * and busy loop.
 
3570
             */
3235
3571
            if (vm_living_thread_num(th->vm) == th->vm->sleeper) {
3236
 
                last_thread = 1;
 
3572
                timeout_ms = 100;
3237
3573
            }
 
3574
            GVL_UNLOCK_BEGIN();
 
3575
            interrupted = lock_func(th, mutex, timeout_ms);
 
3576
            native_mutex_unlock(&mutex->lock);
 
3577
            GVL_UNLOCK_END();
3238
3578
 
3239
 
            th->transition_for_lock = 1;
3240
 
            BLOCKING_REGION_CORE({
3241
 
                interrupted = lock_func(th, mutex, last_thread);
3242
 
            });
3243
 
            th->transition_for_lock = 0;
3244
 
            remove_signal_thread_list(th);
3245
3579
            reset_unblock_function(th, &oldubf);
3246
3580
 
3247
3581
            th->locking_mutex = Qfalse;
3264
3598
}
3265
3599
 
3266
3600
static const char *
3267
 
mutex_unlock(mutex_t *mutex, rb_thread_t volatile *th)
 
3601
rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th)
3268
3602
{
3269
3603
    const char *err = NULL;
3270
 
    mutex_t *th_mutex;
 
3604
    rb_mutex_t *th_mutex;
3271
3605
 
3272
3606
    native_mutex_lock(&mutex->lock);
3273
3607
 
3279
3613
    }
3280
3614
    else {
3281
3615
        mutex->th = 0;
3282
 
        if (mutex->cond_waiting > 0) {
3283
 
            /* waiting thread */
 
3616
        if (mutex->cond_waiting > 0)
3284
3617
            native_cond_signal(&mutex->cond);
3285
 
            mutex->cond_waiting--;
3286
 
            mutex->cond_notified++;
3287
 
        }
3288
3618
    }
3289
3619
 
3290
3620
    native_mutex_unlock(&mutex->lock);
3296
3626
        }
3297
3627
        else {
3298
3628
            while (1) {
3299
 
                mutex_t *tmp_mutex;
 
3629
                rb_mutex_t *tmp_mutex;
3300
3630
                tmp_mutex = th_mutex->next_mutex;
3301
3631
                if (tmp_mutex == mutex) {
3302
3632
                    th_mutex->next_mutex = tmp_mutex->next_mutex;
3322
3652
rb_mutex_unlock(VALUE self)
3323
3653
{
3324
3654
    const char *err;
3325
 
    mutex_t *mutex;
 
3655
    rb_mutex_t *mutex;
3326
3656
    GetMutexPtr(self, mutex);
3327
3657
 
3328
 
    err = mutex_unlock(mutex, GET_THREAD());
 
3658
    err = rb_mutex_unlock_th(mutex, GET_THREAD());
3329
3659
    if (err) rb_raise(rb_eThreadError, "%s", err);
3330
3660
 
3331
3661
    return self;
3332
3662
}
3333
3663
 
3334
3664
static void
3335
 
rb_mutex_unlock_all(mutex_t *mutexes, rb_thread_t *th)
3336
 
{
3337
 
    const char *err;
3338
 
    mutex_t *mutex;
3339
 
 
3340
 
    while (mutexes) {
3341
 
        mutex = mutexes;
3342
 
        /* rb_warn("mutex #<%p> remains to be locked by terminated thread",
3343
 
                mutexes); */
3344
 
        mutexes = mutex->next_mutex;
3345
 
        err = mutex_unlock(mutex, th);
3346
 
        if (err) rb_bug("invalid keeping_mutexes: %s", err);
3347
 
    }
3348
 
}
3349
 
 
3350
 
static void
3351
 
rb_mutex_abandon_all(mutex_t *mutexes)
3352
 
{
3353
 
    mutex_t *mutex;
 
3665
rb_mutex_abandon_all(rb_mutex_t *mutexes)
 
3666
{
 
3667
    rb_mutex_t *mutex;
3354
3668
 
3355
3669
    while (mutexes) {
3356
3670
        mutex = mutexes;
3439
3753
 
3440
3754
static const rb_data_type_t barrier_data_type = {
3441
3755
    "barrier",
3442
 
    barrier_mark, 0, 0,
 
3756
    {barrier_mark, 0, 0,},
3443
3757
};
3444
3758
 
3445
3759
static VALUE
3448
3762
    return TypedData_Wrap_Struct(klass, &barrier_data_type, (void *)mutex_alloc(0));
3449
3763
}
3450
3764
 
3451
 
#define GetBarrierPtr(obj) (VALUE)rb_check_typeddata(obj, &barrier_data_type)
 
3765
#define GetBarrierPtr(obj) ((VALUE)rb_check_typeddata((obj), &barrier_data_type))
3452
3766
 
3453
3767
VALUE
3454
3768
rb_barrier_new(void)
3462
3776
rb_barrier_wait(VALUE self)
3463
3777
{
3464
3778
    VALUE mutex = GetBarrierPtr(self);
3465
 
    mutex_t *m;
 
3779
    rb_mutex_t *m;
3466
3780
 
3467
3781
    if (!mutex) return Qfalse;
3468
3782
    GetMutexPtr(mutex, m);
3716
4030
}
3717
4031
 
3718
4032
/* tracer */
 
4033
#define RUBY_EVENT_REMOVED 0x1000000
 
4034
 
 
4035
enum {
 
4036
    EVENT_RUNNING_NOTHING,
 
4037
    EVENT_RUNNING_TRACE = 1,
 
4038
    EVENT_RUNNING_THREAD = 2,
 
4039
    EVENT_RUNNING_VM = 4,
 
4040
    EVENT_RUNNING_EVENT_MASK = EVENT_RUNNING_VM|EVENT_RUNNING_THREAD
 
4041
};
 
4042
 
 
4043
static VALUE thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always);
 
4044
 
 
4045
struct event_call_args {
 
4046
    rb_thread_t *th;
 
4047
    VALUE klass;
 
4048
    VALUE self;
 
4049
    VALUE proc;
 
4050
    ID id;
 
4051
    rb_event_flag_t event;
 
4052
};
3719
4053
 
3720
4054
static rb_event_hook_t *
3721
4055
alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
3734
4068
    rb_event_flag_t flag = th->event_flags & RUBY_EVENT_VM;
3735
4069
 
3736
4070
    while (hook) {
3737
 
        flag |= hook->flag;
 
4071
        if (!(flag & RUBY_EVENT_REMOVED))
 
4072
            flag |= hook->flag;
3738
4073
        hook = hook->next;
3739
4074
    }
3740
4075
    th->event_flags = flag;
3787
4122
    st_foreach(GET_VM()->living_threads, set_threads_event_flags_i, (st_data_t) flag);
3788
4123
}
3789
4124
 
3790
 
static inline void
 
4125
static inline int
3791
4126
exec_event_hooks(const rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
3792
4127
{
 
4128
    int removed = 0;
3793
4129
    for (; hook; hook = hook->next) {
 
4130
        if (hook->flag & RUBY_EVENT_REMOVED) {
 
4131
            removed++;
 
4132
            continue;
 
4133
        }
3794
4134
        if (flag & hook->flag) {
3795
4135
            (*hook->func)(flag, hook->data, self, id, klass);
3796
4136
        }
3797
4137
    }
 
4138
    return removed;
3798
4139
}
3799
4140
 
3800
 
void
3801
 
rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
 
4141
static int remove_defered_event_hook(rb_event_hook_t **root);
 
4142
 
 
4143
static VALUE
 
4144
thread_exec_event_hooks(VALUE args, int running)
3802
4145
{
3803
 
    const VALUE errinfo = th->errinfo;
 
4146
    struct event_call_args *argp = (struct event_call_args *)args;
 
4147
    rb_thread_t *th = argp->th;
 
4148
    rb_event_flag_t flag = argp->event;
 
4149
    VALUE self = argp->self;
 
4150
    ID id = argp->id;
 
4151
    VALUE klass = argp->klass;
3804
4152
    const rb_event_flag_t wait_event = th->event_flags;
3805
 
 
3806
 
    if (self == rb_mRubyVMFrozenCore) return;
3807
 
    if (wait_event & flag) {
3808
 
        exec_event_hooks(th->event_hooks, flag, self, id, klass);
 
4153
    int removed;
 
4154
 
 
4155
    if (self == rb_mRubyVMFrozenCore) return 0;
 
4156
 
 
4157
    if ((wait_event & flag) && !(running & EVENT_RUNNING_THREAD)) {
 
4158
        th->tracing |= EVENT_RUNNING_THREAD;
 
4159
        removed = exec_event_hooks(th->event_hooks, flag, self, id, klass);
 
4160
        th->tracing &= ~EVENT_RUNNING_THREAD;
 
4161
        if (removed) {
 
4162
            remove_defered_event_hook(&th->event_hooks);
 
4163
        }
3809
4164
    }
3810
4165
    if (wait_event & RUBY_EVENT_VM) {
3811
4166
        if (th->vm->event_hooks == NULL) {
3812
4167
            th->event_flags &= (~RUBY_EVENT_VM);
3813
4168
        }
3814
 
        else {
3815
 
            exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
 
4169
        else if (!(running & EVENT_RUNNING_VM)) {
 
4170
            th->tracing |= EVENT_RUNNING_VM;
 
4171
            removed = exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
 
4172
            th->tracing &= ~EVENT_RUNNING_VM;
 
4173
            if (removed) {
 
4174
                remove_defered_event_hook(&th->vm->event_hooks);
 
4175
            }
3816
4176
        }
3817
4177
    }
 
4178
    return 0;
 
4179
}
 
4180
 
 
4181
void
 
4182
rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
 
4183
{
 
4184
    const VALUE errinfo = th->errinfo;
 
4185
    struct event_call_args args;
 
4186
    args.th = th;
 
4187
    args.event = flag;
 
4188
    args.self = self;
 
4189
    args.id = id;
 
4190
    args.klass = klass;
 
4191
    args.proc = 0;
 
4192
    thread_suppress_tracing(th, EVENT_RUNNING_EVENT_MASK, thread_exec_event_hooks, (VALUE)&args, FALSE);
3818
4193
    th->errinfo = errinfo;
3819
4194
}
3820
4195
 
3831
4206
}
3832
4207
 
3833
4208
static int
 
4209
defer_remove_event_hook(rb_event_hook_t *hook, rb_event_hook_func_t func)
 
4210
{
 
4211
    while (hook) {
 
4212
        if (func == 0 || hook->func == func) {
 
4213
            hook->flag |= RUBY_EVENT_REMOVED;
 
4214
        }
 
4215
        hook = hook->next;
 
4216
    }
 
4217
    return -1;
 
4218
}
 
4219
 
 
4220
static int
3834
4221
remove_event_hook(rb_event_hook_t **root, rb_event_hook_func_t func)
3835
4222
{
3836
 
    rb_event_hook_t *prev = NULL, *hook = *root, *next;
3837
 
 
3838
 
    while (hook) {
3839
 
        next = hook->next;
3840
 
        if (func == 0 || hook->func == func) {
3841
 
            if (prev) {
3842
 
                prev->next = hook->next;
3843
 
            }
3844
 
            else {
3845
 
                *root = hook->next;
3846
 
            }
3847
 
            xfree(hook);
3848
 
        }
3849
 
        else {
3850
 
            prev = hook;
3851
 
        }
3852
 
        hook = next;
3853
 
    }
3854
 
    return -1;
3855
 
}
3856
 
 
3857
 
static int
3858
 
rb_threadptr_revmove_event_hook(rb_thread_t *th, rb_event_hook_func_t func)
3859
 
{
3860
 
    int ret = remove_event_hook(&th->event_hooks, func);
 
4223
    rb_event_hook_t *hook = *root, *next;
 
4224
 
 
4225
    while (hook) {
 
4226
        next = hook->next;
 
4227
        if (func == 0 || hook->func == func || (hook->flag & RUBY_EVENT_REMOVED)) {
 
4228
            *root = next;
 
4229
            xfree(hook);
 
4230
        }
 
4231
        else {
 
4232
            root = &hook->next;
 
4233
        }
 
4234
        hook = next;
 
4235
    }
 
4236
    return -1;
 
4237
}
 
4238
 
 
4239
static int
 
4240
remove_defered_event_hook(rb_event_hook_t **root)
 
4241
{
 
4242
    rb_event_hook_t *hook = *root, *next;
 
4243
 
 
4244
    while (hook) {
 
4245
        next = hook->next;
 
4246
        if (hook->flag & RUBY_EVENT_REMOVED) {
 
4247
            *root = next;
 
4248
            xfree(hook);
 
4249
        }
 
4250
        else {
 
4251
            root = &hook->next;
 
4252
        }
 
4253
        hook = next;
 
4254
    }
 
4255
    return -1;
 
4256
}
 
4257
 
 
4258
static int
 
4259
rb_threadptr_remove_event_hook(rb_thread_t *th, rb_event_hook_func_t func)
 
4260
{
 
4261
    int ret;
 
4262
    if (th->tracing & EVENT_RUNNING_THREAD) {
 
4263
        ret = defer_remove_event_hook(th->event_hooks, func);
 
4264
    }
 
4265
    else {
 
4266
        ret = remove_event_hook(&th->event_hooks, func);
 
4267
    }
3861
4268
    thread_reset_event_flags(th);
3862
4269
    return ret;
3863
4270
}
3865
4272
int
3866
4273
rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func)
3867
4274
{
3868
 
    return rb_threadptr_revmove_event_hook(thval2thread_t(thval), func);
 
4275
    return rb_threadptr_remove_event_hook(thval2thread_t(thval), func);
 
4276
}
 
4277
 
 
4278
static rb_event_hook_t *
 
4279
search_live_hook(rb_event_hook_t *hook)
 
4280
{
 
4281
    while (hook) {
 
4282
        if (!(hook->flag & RUBY_EVENT_REMOVED))
 
4283
            return hook;
 
4284
        hook = hook->next;
 
4285
    }
 
4286
    return NULL;
 
4287
}
 
4288
 
 
4289
static int
 
4290
running_vm_event_hooks(st_data_t key, st_data_t val, st_data_t data)
 
4291
{
 
4292
    rb_thread_t *th = thval2thread_t((VALUE)key);
 
4293
    if (!(th->tracing & EVENT_RUNNING_VM)) return ST_CONTINUE;
 
4294
    *(rb_thread_t **)data = th;
 
4295
    return ST_STOP;
 
4296
}
 
4297
 
 
4298
static rb_thread_t *
 
4299
vm_event_hooks_running_thread(rb_vm_t *vm)
 
4300
{
 
4301
    rb_thread_t *found = NULL;
 
4302
    st_foreach(vm->living_threads, running_vm_event_hooks, (st_data_t)&found);
 
4303
    return found;
3869
4304
}
3870
4305
 
3871
4306
int
3872
4307
rb_remove_event_hook(rb_event_hook_func_t func)
3873
4308
{
3874
4309
    rb_vm_t *vm = GET_VM();
3875
 
    rb_event_hook_t *hook = vm->event_hooks;
3876
 
    int ret = remove_event_hook(&vm->event_hooks, func);
3877
 
 
3878
 
    if (hook != NULL && vm->event_hooks == NULL) {
 
4310
    rb_event_hook_t *hook = search_live_hook(vm->event_hooks);
 
4311
    int ret;
 
4312
 
 
4313
    if (vm_event_hooks_running_thread(vm)) {
 
4314
        ret = defer_remove_event_hook(vm->event_hooks, func);
 
4315
    }
 
4316
    else {
 
4317
        ret = remove_event_hook(&vm->event_hooks, func);
 
4318
    }
 
4319
 
 
4320
    if (hook && !search_live_hook(vm->event_hooks)) {
3879
4321
        set_threads_event_flags(0);
3880
4322
    }
3881
4323
 
3887
4329
{
3888
4330
    rb_thread_t *th;
3889
4331
    GetThreadPtr((VALUE)key, th);
3890
 
    rb_threadptr_revmove_event_hook(th, 0);
 
4332
    rb_threadptr_remove_event_hook(th, 0);
3891
4333
    return ST_CONTINUE;
3892
4334
}
3893
4335
 
3949
4391
    rb_remove_event_hook(call_trace_func);
3950
4392
 
3951
4393
    if (NIL_P(trace)) {
 
4394
        GET_THREAD()->tracing = EVENT_RUNNING_NOTHING;
3952
4395
        return Qnil;
3953
4396
    }
3954
4397
 
4002
4445
{
4003
4446
    rb_thread_t *th;
4004
4447
    GetThreadPtr(obj, th);
4005
 
    rb_threadptr_revmove_event_hook(th, call_trace_func);
 
4448
    rb_threadptr_remove_event_hook(th, call_trace_func);
4006
4449
 
4007
4450
    if (NIL_P(trace)) {
 
4451
        th->tracing = EVENT_RUNNING_NOTHING;
4008
4452
        return Qnil;
4009
4453
    }
4010
4454
    thread_add_trace_func(th, trace);
4036
4480
    }
4037
4481
}
4038
4482
 
4039
 
VALUE ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always);
4040
 
 
4041
 
struct call_trace_func_args {
4042
 
    rb_event_flag_t event;
4043
 
    VALUE proc;
4044
 
    VALUE self;
4045
 
    ID id;
4046
 
    VALUE klass;
4047
 
};
4048
 
 
4049
4483
static VALUE
4050
4484
call_trace_proc(VALUE args, int tracing)
4051
4485
{
4052
 
    struct call_trace_func_args *p = (struct call_trace_func_args *)args;
 
4486
    struct event_call_args *p = (struct event_call_args *)args;
4053
4487
    const char *srcfile = rb_sourcefile();
4054
4488
    VALUE eventname = rb_str_new2(get_event_name(p->event));
4055
4489
    VALUE filename = srcfile ? rb_str_new2(srcfile) : Qnil;
4058
4492
    ID id = 0;
4059
4493
    VALUE klass = 0;
4060
4494
 
4061
 
    if (p->event == RUBY_EVENT_C_CALL ||
4062
 
        p->event == RUBY_EVENT_C_RETURN) {
 
4495
    if (p->klass != 0) {
4063
4496
        id = p->id;
4064
4497
        klass = p->klass;
4065
4498
    }
4066
4499
    else {
4067
 
        rb_thread_method_id_and_class(GET_THREAD(), &id, &klass);
 
4500
        rb_thread_method_id_and_class(p->th, &id, &klass);
4068
4501
    }
4069
4502
    if (id == ID_ALLOCATOR)
4070
4503
      return Qnil;
4090
4523
static void
4091
4524
call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
4092
4525
{
4093
 
    struct call_trace_func_args args;
 
4526
    struct event_call_args args;
4094
4527
 
 
4528
    args.th = GET_THREAD();
4095
4529
    args.event = event;
4096
4530
    args.proc = proc;
4097
4531
    args.self = self;
4104
4538
ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always)
4105
4539
{
4106
4540
    rb_thread_t *th = GET_THREAD();
4107
 
    int state, tracing;
 
4541
    return thread_suppress_tracing(th, EVENT_RUNNING_TRACE, func, arg, always);
 
4542
}
 
4543
 
 
4544
static VALUE
 
4545
thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always)
 
4546
{
 
4547
    int state, tracing = th->tracing, running = tracing & ev;
4108
4548
    volatile int raised;
4109
4549
    volatile int outer_state;
4110
4550
    VALUE result = Qnil;
4111
4551
 
4112
 
    if ((tracing = th->tracing) != 0 && !always) {
 
4552
    if (running == ev && !always) {
4113
4553
        return Qnil;
4114
4554
    }
4115
4555
    else {
4116
 
        th->tracing = 1;
 
4556
        th->tracing |= ev;
4117
4557
    }
4118
4558
 
4119
4559
    raised = rb_threadptr_reset_raised(th);
4122
4562
 
4123
4563
    PUSH_TAG();
4124
4564
    if ((state = EXEC_TAG()) == 0) {
4125
 
        result = (*func)(arg, tracing);
 
4565
        result = (*func)(arg, running);
4126
4566
    }
4127
4567
 
4128
4568
    if (raised) {
4139
4579
    return result;
4140
4580
}
4141
4581
 
4142
 
VALUE rb_thread_backtrace(VALUE thval);
4143
 
 
4144
4582
/*
4145
4583
 *  call-seq:
4146
4584
 *     thr.backtrace    -> array
4184
4622
#define rb_intern(str) rb_intern_const(str)
4185
4623
 
4186
4624
    VALUE cThGroup;
 
4625
    rb_thread_t *th = GET_THREAD();
4187
4626
 
4188
4627
    rb_define_singleton_method(rb_cThread, "new", thread_s_new, -1);
4189
4628
    rb_define_singleton_method(rb_cThread, "start", thread_start, -2);
4228
4667
 
4229
4668
    rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
4230
4669
 
 
4670
    closed_stream_error = rb_exc_new2(rb_eIOError, "stream closed");
 
4671
    OBJ_TAINT(closed_stream_error);
 
4672
    OBJ_FREEZE(closed_stream_error);
 
4673
 
4231
4674
    cThGroup = rb_define_class("ThreadGroup", rb_cObject);
4232
4675
    rb_define_alloc_func(cThGroup, thgroup_s_alloc);
4233
4676
    rb_define_method(cThGroup, "list", thgroup_list, 0);
4236
4679
    rb_define_method(cThGroup, "add", thgroup_add, 1);
4237
4680
 
4238
4681
    {
4239
 
        rb_thread_t *th = GET_THREAD();
4240
4682
        th->thgroup = th->vm->thgroup_default = rb_obj_alloc(cThGroup);
4241
4683
        rb_define_const(cThGroup, "Default", th->thgroup);
4242
4684
    }
4263
4705
        /* main thread setting */
4264
4706
        {
4265
4707
            /* acquire global vm lock */
4266
 
            rb_thread_lock_t *lp = &GET_THREAD()->vm->global_vm_lock;
4267
 
            native_mutex_initialize(lp);
4268
 
            native_mutex_lock(lp);
4269
 
            native_mutex_initialize(&GET_THREAD()->interrupt_lock);
 
4708
            gvl_init(th->vm);
 
4709
            gvl_acquire(th->vm, th);
 
4710
            native_mutex_initialize(&th->interrupt_lock);
4270
4711
        }
4271
4712
    }
4272
4713
 
4273
4714
    rb_thread_create_timer_thread();
4274
4715
 
 
4716
    /* suppress warnings on cygwin, mingw and mswin.*/
4275
4717
    (void)native_mutex_trylock;
4276
 
    (void)ruby_thread_set_native;
4277
4718
}
4278
4719
 
4279
4720
int
4291
4732
    rb_thread_t *th;
4292
4733
    GetThreadPtr(thval, th);
4293
4734
 
4294
 
    if (th->status != THREAD_STOPPED_FOREVER || RUBY_VM_INTERRUPTED(th) || th->transition_for_lock) {
 
4735
    if (th->status != THREAD_STOPPED_FOREVER || RUBY_VM_INTERRUPTED(th)) {
4295
4736
        *found = 1;
4296
4737
    }
4297
4738
    else if (th->locking_mutex) {
4298
 
        mutex_t *mutex;
 
4739
        rb_mutex_t *mutex;
4299
4740
        GetMutexPtr(th->locking_mutex, mutex);
4300
4741
 
4301
4742
        native_mutex_lock(&mutex->lock);
4302
 
        if (mutex->th == th || (!mutex->th && mutex->cond_notified)) {
 
4743
        if (mutex->th == th || (!mutex->th && mutex->cond_waiting)) {
4303
4744
            *found = 1;
4304
4745
        }
4305
4746
        native_mutex_unlock(&mutex->lock);
4308
4749
    return (*found) ? ST_STOP : ST_CONTINUE;
4309
4750
}
4310
4751
 
4311
 
#if 0 /* for debug */
 
4752
#ifdef DEBUG_DEADLOCK_CHECK
4312
4753
static int
4313
4754
debug_i(st_data_t key, st_data_t val, int *found)
4314
4755
{
4316
4757
    rb_thread_t *th;
4317
4758
    GetThreadPtr(thval, th);
4318
4759
 
4319
 
    printf("th:%p %d %d %d", th, th->status, th->interrupt_flag, th->transition_for_lock);
 
4760
    printf("th:%p %d %d", th, th->status, th->interrupt_flag);
4320
4761
    if (th->locking_mutex) {
4321
 
        mutex_t *mutex;
 
4762
        rb_mutex_t *mutex;
4322
4763
        GetMutexPtr(th->locking_mutex, mutex);
4323
4764
 
4324
4765
        native_mutex_lock(&mutex->lock);
4325
 
        printf(" %p %d\n", mutex->th, mutex->cond_notified);
 
4766
        printf(" %p %d\n", mutex->th, mutex->cond_waiting);
4326
4767
        native_mutex_unlock(&mutex->lock);
4327
4768
    }
4328
 
    else puts("");
 
4769
    else
 
4770
        puts("");
4329
4771
 
4330
4772
    return ST_CONTINUE;
4331
4773
}
4345
4787
        VALUE argv[2];
4346
4788
        argv[0] = rb_eFatal;
4347
4789
        argv[1] = rb_str_new2("deadlock detected");
4348
 
#if 0 /* for debug */
 
4790
#ifdef DEBUG_DEADLOCK_CHECK
4349
4791
        printf("%d %d %p %p\n", vm->living_threads->num_entries, vm->sleeper, GET_THREAD(), vm->main_thread);
4350
4792
        st_foreach(vm->living_threads, debug_i, (st_data_t)0);
4351
4793
#endif
4390
4832
    GET_VM()->coverages = Qfalse;
4391
4833
    rb_remove_event_hook(update_coverage);
4392
4834
}
 
4835