final-queue.patch

patch with proposed alterations: Queue, SizedQueue and ConditionVariable in C - Ricardo Panaggio, 07/28/2010 02:51 AM

Download (18 KB)

View differences:

.gitignore
397 397
/ext/syslog/syslog.a
398 398
/ext/syslog/conftest.dSYM
399 399

  
400
# /ext/thread/
401
/ext/thread/Makefile
402
/ext/thread/extconf.h
403

  
400 404
# /ext/tmpdir/
401 405
/ext/tmpdir/Makefile
402 406
/ext/tmpdir/extconf.h
ext/thread/extconf.rb
1
create_makefile('extthread')
ext/thread/extthread.c
1
#include <ruby.h>
2

  
3
RUBY_EXTERN size_t rb_objspace_data_type_memsize(VALUE);
4
RUBY_EXTERN size_t rb_ary_memsize(VALUE);
5

  
6
static VALUE
7
rb_ary_buf_new(void)
8
{
9
    VALUE ary = rb_ary_tmp_new(1);
10
    OBJ_UNTRUST(ary);
11
    return ary;
12
}
13

  
14
static void
15
wakeup_first_thread(VALUE list)
16
{
17
    VALUE thread;
18

  
19
    while (!NIL_P(thread = rb_ary_shift(list))) {
20
       if (RTEST(rb_thread_wakeup_alive(thread))) break;
21
    }
22
}
23

  
24
static void
25
wakeup_all_threads(VALUE list)
26
{
27
    VALUE thread, list0 = list;
28
    long i;
29

  
30
    list = rb_ary_subseq(list, 0, LONG_MAX);
31
    rb_ary_clear(list0);
32
    for (i = 0; i < RARRAY_LEN(list); ++i) {
33
       thread = RARRAY_PTR(list)[i];
34
       rb_thread_wakeup_alive(thread);
35
    }
36
    RB_GC_GUARD(list);
37
}
38

  
39
/*
40
 *  Document-class: ConditionVariable
41
 *
42
 *  ConditionVariable objects augment class Mutex. Using condition variables,
43
 *  it is possible to suspend while in the middle of a critical section until a
44
 *  resource becomes available.
45
 *
46
 *  Example:
47
 *
48
 *    require 'thread'
49
 *
50
 *    mutex = Mutex.new
51
 *    resource = ConditionVariable.new
52
 *
53
 *    a = Thread.new {
54
 *      mutex.synchronize {
55
 *        # Thread 'a' now needs the resource
56
 *        resource.wait(mutex)
57
 *        # 'a' can now have the resource
58
 *      }
59
 *    }
60
 *
61
 *    b = Thread.new {
62
 *      mutex.synchronize {
63
 *        # Thread 'b' has finished using the resource
64
 *        resource.signal
65
 *      }
66
 *    }
67
 */
68

  
69
typedef struct {
70
    VALUE waiters;
71
} CondVar;
72

  
73
static void
74
condvar_mark(void *ptr)
75
{
76
    CondVar *condvar = ptr;
77
    rb_gc_mark(condvar->waiters);
78
}
79

  
80
#define condvar_free RUBY_TYPED_DEFAULT_FREE
81

  
82
static size_t
83
condvar_memsize(const void *ptr)
84
{
85
    size_t size = 0;
86
    if (ptr) {
87
       const CondVar *condvar = ptr;
88
       size = sizeof(CondVar);
89
       size += rb_ary_memsize(condvar->waiters);
90
    }
91
    return size;
92
}
93

  
94
static const rb_data_type_t condvar_data_type = {
95
    "condvar",
96
    {condvar_mark, condvar_free, condvar_memsize,},
97
};
98

  
99
#define GetCondVarPtr(obj, tobj) \
100
    TypedData_Get_Struct(obj, CondVar, &condvar_data_type, tobj)
101

  
102
static CondVar *
103
get_condvar_ptr(VALUE self)
104
{
105
    CondVar *condvar;
106
    GetCondVarPtr(self, condvar);
107
    if (!condvar->waiters) {
108
       rb_raise(rb_eArgError, "uninitialized CondionVariable");
109
    }
110
    return condvar;
111
}
112

  
113
static VALUE
114
condvar_alloc(VALUE klass)
115
{
116
    CondVar *condvar;
117
    return TypedData_Make_Struct(klass, CondVar, &condvar_data_type, condvar);
118
}
119

  
120
static void
121
condvar_initialize(CondVar *condvar)
122
{
123
    condvar->waiters = rb_ary_buf_new();
124
}
125

  
126
/*
127
 * Document-method: new
128
 * call-seq: new
129
 *
130
 * Creates a new condvar.
131
 */
132

  
133
static VALUE
134
rb_condvar_initialize(VALUE self)
135
{
136
    CondVar *condvar;
137
    GetCondVarPtr(self, condvar);
138

  
139
    condvar_initialize(condvar);
140

  
141
    return self;
142
}
143

  
144
struct sleep_call {
145
    int argc;
146
    VALUE *argv;
147
};
148

  
149
static VALUE
150
do_sleep(VALUE args)
151
{
152
    struct sleep_call *p = (struct sleep_call *)args;
153
    return rb_funcall(p->argv[0], rb_intern("sleep"), p->argc-1, p->argv+1);
154
}
155

  
156
static VALUE
157
delete_current_thread(VALUE ary)
158
{
159
    return rb_ary_delete(ary, rb_thread_current());
160
}
161

  
162
/*
163
 * Document-method: wait
164
 * call-seq: wait(mutex, timeout=nil)
165
 *
166
 * Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
167
 *
168
 * If +timeout+ is given, this method returns after +timeout+ seconds passed,
169
 * even if no other thread doesn't signal.
170
 */
171

  
172
static VALUE
173
rb_condvar_wait(int argc, VALUE *argv, VALUE self)
174
{
175
    VALUE waiters = get_condvar_ptr(self)->waiters;
176
    struct sleep_call args;
177

  
178
    args.argc = argc;
179
    args.argv = argv;
180
    rb_ary_push(waiters, rb_thread_current());
181
    rb_ensure(do_sleep, (VALUE)&args, delete_current_thread, waiters);
182
    return self;
183
}
184

  
185
/*
186
 * Document-method: signal
187
 * call-seq: signal
188
 *
189
 * Wakes up the first thread in line waiting for this lock.
190
 */
191

  
192
static VALUE
193
rb_condvar_signal(VALUE self)
194
{
195
    wakeup_first_thread(get_condvar_ptr(self)->waiters);
196
    return self;
197
}
198

  
199
/*
200
 * Document-method: broadcast
201
 * call-seq: broadcast
202
 *
203
 * Wakes up all threads waiting for this lock.
204
 */
205

  
206
static VALUE
207
rb_condvar_broadcast(VALUE self)
208
{
209
    wakeup_all_threads(get_condvar_ptr(self)->waiters);
210
    return self;
211
}
212

  
213
/*
214
 *  Document-class: Queue
215
 *
216
 *  This class provides a way to synchronize communication between threads.
217
 *
218
 *  Example:
219
 *
220
 *    require 'thread'
221
 *    queue = Queue.new
222
 *
223
 *  producer = Thread.new do
224
 *    5.times do |i|
225
 *      sleep rand(i) # simulate expense
226
 *      queue << i
227
 *      puts "#{i} produced"
228
 *    end
229
 *  end
230
 *
231
 *  consumer = Thread.new do
232
 *    5.times do |i|
233
 *      value = queue.pop
234
 *      sleep rand(i/2) # simulate expense
235
 *      puts "consumed #{value}"
236
 *    end
237
 *  end
238
 *
239
 */
240

  
241
typedef struct {
242
    VALUE mutex;
243
    VALUE que;
244
    VALUE waiting;
245
} Queue;
246

  
247
static void
248
queue_mark(void *ptr)
249
{
250
    Queue *queue = ptr;
251
    rb_gc_mark(queue->mutex);
252
    rb_gc_mark(queue->que);
253
    rb_gc_mark(queue->waiting);
254
}
255

  
256
#define queue_free RUBY_TYPED_DEFAULT_FREE
257

  
258
static size_t
259
queue_memsize(const void *ptr)
260
{
261
    size_t size = 0;
262
    if (ptr) {
263
       const Queue *queue = ptr;
264
       size = sizeof(Queue);
265
       size += rb_objspace_data_type_memsize(queue->mutex);
266
       size += rb_ary_memsize(queue->que);
267
       size += rb_ary_memsize(queue->waiting);
268
    }
269
    return size;
270
}
271

  
272
static const rb_data_type_t queue_data_type = {
273
    "queue",
274
    {queue_mark, queue_free, queue_memsize,},
275
};
276

  
277
#define GetQueuePtr(obj, tobj) \
278
    TypedData_Get_Struct(obj, Queue, &queue_data_type, tobj)
279

  
280
static Queue *
281
get_queue_ptr(VALUE self)
282
{
283
    Queue *queue;
284
    GetQueuePtr(self, queue);
285
    if (!queue->mutex || !queue->que || !queue->waiting) {
286
       rb_raise(rb_eArgError, "uninitialized Queue");
287
    }
288
    return queue;
289
}
290

  
291
static VALUE
292
queue_alloc(VALUE klass)
293
{
294
    Queue *queue;
295
    return TypedData_Make_Struct(klass, Queue, &queue_data_type, queue);
296
}
297

  
298
static void
299
queue_initialize(Queue *queue)
300
{
301
    queue->mutex = rb_mutex_new();
302
    RBASIC(queue->mutex)->klass = 0;
303
    queue->que = rb_ary_buf_new();
304
    queue->waiting = rb_ary_buf_new();
305
}
306

  
307
/*
308
 * Document-method: new
309
 * call-seq: new
310
 *
311
 * Creates a new queue.
312
 */
313

  
314
static VALUE
315
rb_queue_initialize(VALUE self)
316
{
317
    Queue *queue;
318
    GetQueuePtr(self, queue);
319

  
320
    queue_initialize(queue);
321

  
322
    return self;
323
}
324

  
325
struct synchronize_call_args {
326
    Queue *queue;
327
    VALUE (*func)(Queue *queue, VALUE arg);
328
    VALUE arg;
329
};
330

  
331
static VALUE
332
queue_synchronize_call(VALUE args)
333
{
334
    struct synchronize_call_args *p = (struct synchronize_call_args *)args;
335
    return (*p->func)(p->queue, p->arg);
336
}
337

  
338
static VALUE
339
queue_synchronize(Queue *queue, VALUE (*func)(Queue *queue, VALUE arg), VALUE arg)
340
{
341
    struct synchronize_call_args args;
342
    args.queue = queue;
343
    args.func = func;
344
    args.arg = arg;
345
    rb_mutex_lock(queue->mutex);
346
    return rb_ensure(queue_synchronize_call, (VALUE)&args, rb_mutex_unlock, queue->mutex);
347
}
348

  
349
static VALUE
350
queue_do_push(Queue *queue, VALUE obj)
351
{
352
    rb_ary_push(queue->que, obj);
353
    wakeup_first_thread(queue->waiting);
354
    return Qnil;
355
}
356

  
357
/*
358
 * Document-method: push
359
 * call-seq: push(obj)
360
 *
361
 * Pushes +obj+ to the queue.
362
 */
363

  
364
static VALUE
365
rb_queue_push(VALUE self, VALUE obj)
366
{
367
    queue_synchronize(get_queue_ptr(self), queue_do_push, obj);
368
    return self;
369
}
370

  
371
static VALUE
372
queue_do_pop(Queue *queue, VALUE should_block)
373
{
374
    while (!RARRAY_LEN(queue->que)) {
375
       if (!(int)should_block) {
376
           rb_raise(rb_eThreadError, "queue empty");
377
       }
378
       rb_ary_push(queue->waiting, rb_thread_current());
379
       rb_mutex_sleep(queue->mutex, Qnil);
380
    }
381

  
382
    return rb_ary_shift(queue->que);
383
}
384

  
385
static int
386
queue_pop_should_block(int argc, VALUE *argv)
387
{
388
    int should_block = 1;
389
    switch (argc) {
390
      case 0:
391
       break;
392
      case 1:
393
       should_block = !RTEST(argv[0]);
394
       break;
395
      default:
396
       rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
397
    }
398
    return should_block;
399
}
400

  
401
/*
402
 * Document-method: pop
403
 * call_seq: pop(non_block=false)
404
 *
405
 * Retrieves data from the queue.  If the queue is empty, the calling thread is
406
 * suspended until data is pushed onto the queue.  If +non_block+ is true, the
407
 * thread isn't suspended, and an exception is raised.
408
 */
409

  
410
static VALUE
411
rb_queue_pop(int argc, VALUE *argv, VALUE self)
412
{
413
    Queue *queue = get_queue_ptr(self);
414
    int should_block = queue_pop_should_block(argc, argv);
415
    return queue_synchronize(queue, queue_do_pop, (VALUE)should_block);
416
}
417

  
418
static inline unsigned long
419
queue_length(Queue *queue)
420
{
421
    return (unsigned long)RARRAY_LEN(queue->que);
422
}
423

  
424
static inline unsigned long
425
queue_num_waiting(Queue *queue)
426
{
427
    return (unsigned long)RARRAY_LEN(queue->waiting);
428
}
429

  
430
/*
431
 * Document-method: empty?
432
 * call-seq: empty?
433
 *
434
 * Returns +true+ if the queue is empty.
435
 */
436

  
437
static VALUE
438
rb_queue_empty_p(VALUE self)
439
{
440
    return queue_length(get_queue_ptr(self)) == 0 ? Qtrue : Qfalse;
441
}
442

  
443
/*
444
 * Document-method: clear
445
 * call-seq: clear
446
 *
447
 * Removes all objects from the queue.
448
 */
449

  
450
static VALUE
451
rb_queue_clear(VALUE self)
452
{
453
    Queue *queue = get_queue_ptr(self);
454

  
455
    rb_ary_clear(queue->que);
456

  
457
    return self;
458
}
459

  
460
/*
461
 * Document-method: length
462
 * call-seq: length
463
 *
464
 * Returns the length of the queue.
465
 */
466

  
467
static VALUE
468
rb_queue_length(VALUE self)
469
{
470
    unsigned long len = queue_length(get_queue_ptr(self));
471
    return ULONG2NUM(len);
472
}
473

  
474
/*
475
 * Document-method: num_waiting
476
 * call-seq: num_waiting
477
 *
478
 * Returns the number of threads waiting on the queue.
479
 */
480

  
481
static VALUE
482
rb_queue_num_waiting(VALUE self)
483
{
484
    long len = queue_num_waiting(get_queue_ptr(self));
485
    return ULONG2NUM(len);
486
}
487

  
488
/*
489
 *  Document-class: SizedQueue
490
 *
491
 * This class represents queues of specified size capacity.  The push operation
492
 * may be blocked if the capacity is full.
493
 *
494
 * See Queue for an example of how a SizedQueue works.
495
 */
496

  
497
typedef struct  {
498
    Queue queue_;
499
    VALUE queue_wait;
500
    unsigned long max;
501
} SizedQueue;
502

  
503
static void
504
szqueue_mark(void *ptr)
505
{
506
    SizedQueue *szqueue = ptr;
507
    queue_mark(&szqueue->queue_);
508
    rb_gc_mark(szqueue->queue_wait);
509
}
510

  
511
#define szqueue_free queue_free
512

  
513
static size_t
514
szqueue_memsize(const void *ptr)
515
{
516
    size_t size = 0;
517
    if (ptr) {
518
       const SizedQueue *szqueue = ptr;
519
       size = sizeof(SizedQueue) - sizeof(Queue);
520
       size += queue_memsize(&szqueue->queue_);
521
       size += rb_ary_memsize(szqueue->queue_wait);
522
    }
523
    return size;
524
}
525

  
526
static const rb_data_type_t szqueue_data_type = {
527
    "sized_queue",
528
    {szqueue_mark, szqueue_free, szqueue_memsize,},
529
    &queue_data_type,
530
};
531

  
532
#define GetSizedQueuePtr(obj, tobj) \
533
    TypedData_Get_Struct(obj, SizedQueue, &szqueue_data_type, tobj)
534

  
535
static SizedQueue *
536
get_szqueue_ptr(VALUE self)
537
{
538
    SizedQueue *szqueue;
539
    GetSizedQueuePtr(self, szqueue);
540
    if (!szqueue->queue_.mutex || !szqueue->queue_.que || !szqueue->queue_.waiting || !szqueue->queue_wait) {
541
       rb_raise(rb_eArgError, "uninitialized Queue");
542
    }
543
    return szqueue;
544
}
545

  
546
static VALUE
547
szqueue_alloc(VALUE klass)
548
{
549
    SizedQueue *szqueue;
550
    return TypedData_Make_Struct(klass, SizedQueue, &szqueue_data_type, szqueue);
551
}
552

  
553
/*
554
 * Document-method: new
555
 * call-seq: new(max)
556
 *
557
 * Creates a fixed-length queue with a maximum size of +max+.
558
 */
559

  
560
static VALUE
561
rb_szqueue_initialize(VALUE self, VALUE vmax)
562
{
563
    long max;
564
    SizedQueue *szqueue;
565
    GetSizedQueuePtr(self, szqueue);
566

  
567
    max = NUM2LONG(vmax);
568
    if (max <= 0) {
569
       rb_raise(rb_eArgError, "queue size must be positive");
570
    }
571
    queue_initialize(&szqueue->queue_);
572
    szqueue->queue_wait = rb_ary_buf_new();
573
    szqueue->max = (unsigned long)max;
574

  
575
    return self;
576
}
577

  
578
/*
579
 * Document-method: max
580
 * call-seq: max
581
 *
582
 * Returns the maximum size of the queue.
583
 */
584

  
585
static VALUE
586
rb_szqueue_max_get(VALUE self)
587
{
588
    unsigned long max = get_szqueue_ptr(self)->max;
589
    return ULONG2NUM(max);
590
}
591

  
592
/*
593
 * Document-method: max=
594
 * call-seq: max=(n)
595
 *
596
 * Sets the maximum size of the queue.
597
 */
598

  
599
static VALUE
600
rb_szqueue_max_set(VALUE self, VALUE vmax)
601
{
602
    SizedQueue *szqueue = get_szqueue_ptr(self);
603
    long max = NUM2LONG(vmax), diff = 0;
604
    VALUE t;
605

  
606
    if (max <= 0) {
607
       rb_raise(rb_eArgError, "queue size must be positive");
608
    }
609
    if ((unsigned long)max > szqueue->max) {
610
       diff = max - szqueue->max;
611
    }
612
    szqueue->max = max;
613
    while (diff > 0 && !NIL_P(t = rb_ary_shift(szqueue->queue_wait))) {
614
       rb_thread_wakeup_alive(t);
615
    }
616
    return vmax;
617
}
618

  
619
static VALUE
620
szqueue_do_push(Queue *queue, VALUE obj)
621
{
622
    SizedQueue *szqueue = (SizedQueue *)queue;
623

  
624
    while (queue_length(queue) >= szqueue->max) {
625
       rb_ary_push(szqueue->queue_wait, rb_thread_current());
626
       rb_mutex_sleep(queue->mutex, Qnil);
627
    }
628
    return queue_do_push(queue, obj);
629
}
630

  
631
/*
632
 * Document-method: push
633
 * call-seq: push(obj)
634
 *
635
 * Pushes +obj+ to the queue.  If there is no space left in the queue, waits
636
 * until space becomes available.
637
 */
638

  
639
static VALUE
640
rb_szqueue_push(VALUE self, VALUE obj)
641
{
642
    queue_synchronize(&get_szqueue_ptr(self)->queue_, szqueue_do_push, obj);
643
    return self;
644
}
645

  
646
static VALUE
647
szqueue_do_pop(Queue *queue, VALUE should_block)
648
{
649
    SizedQueue *szqueue = (SizedQueue *)queue;
650
    VALUE retval = queue_do_pop(queue, should_block);
651

  
652
    if (queue_length(queue) < szqueue->max) {
653
       wakeup_first_thread(szqueue->queue_wait);
654
    }
655

  
656
    return retval;
657
}
658

  
659
/*
660
 * Document-method: pop
661
 * call_seq: pop(non_block=false)
662
 *
663
 * Returns the number of threads waiting on the queue.
664
 */
665

  
666
static VALUE
667
rb_szqueue_pop(int argc, VALUE *argv, VALUE self)
668
{
669
    SizedQueue *szqueue = get_szqueue_ptr(self);
670
    int should_block = queue_pop_should_block(argc, argv);
671
    return queue_synchronize(&szqueue->queue_, szqueue_do_pop, (VALUE)should_block);
672
}
673

  
674
/*
675
 * Document-method: pop
676
 * call_seq: pop(non_block=false)
677
 *
678
 * Returns the number of threads waiting on the queue.
679
 */
680

  
681
static VALUE
682
rb_szqueue_num_waiting(VALUE self)
683
{
684
    SizedQueue *szqueue = get_szqueue_ptr(self);
685
    long len = queue_num_waiting(&szqueue->queue_);
686
    len += RARRAY_LEN(szqueue->queue_wait);
687
    return ULONG2NUM(len);
688
}
689

  
690
#ifndef UNDER_THREAD
691
#define UNDER_THREAD 1
692
#endif
693

  
694
void
695
Init_extthread(void)
696
{
697
#if UNDER_THREAD
698
#define DEFINE_CLASS_UNDER_THREAD(name, super) rb_define_class_under(rb_cThread, #name, super)
699
#define ALIAS_GLOBCAL_CONST(name) do {                 \
700
       ID id = rb_intern_const(#name);                 \
701
       if (!rb_const_defined_at(rb_cObject, id)) {     \
702
           rb_const_set(rb_cObject, id, rb_c##name);   \
703
       }                                               \
704
    } while (0)
705
#else
706
#define DEFINE_CLASS_UNDER_THREAD(name, super) rb_define_class(name, super)
707
#define ALIAS_GLOBCAL_CONST(name) do { /* nothing */ } while (0)
708
#endif
709
    VALUE rb_cConditionVariable = DEFINE_CLASS_UNDER_THREAD(ConditionVariable, rb_cObject);
710
    VALUE rb_cQueue = DEFINE_CLASS_UNDER_THREAD(Queue, rb_cObject);
711
    VALUE rb_cSizedQueue = DEFINE_CLASS_UNDER_THREAD(SizedQueue, rb_cQueue);
712

  
713
    rb_define_alloc_func(rb_cConditionVariable, condvar_alloc);
714
    rb_define_method(rb_cConditionVariable, "initialize", rb_condvar_initialize, 0);
715
    rb_define_method(rb_cConditionVariable, "wait", rb_condvar_wait, -1);
716
    rb_define_method(rb_cConditionVariable, "signal", rb_condvar_signal, 0);
717
    rb_define_method(rb_cConditionVariable, "broadcast", rb_condvar_broadcast, 0);
718

  
719
    rb_define_alloc_func(rb_cQueue, queue_alloc);
720
    rb_define_method(rb_cQueue, "initialize", rb_queue_initialize, 0);
721
    rb_define_method(rb_cQueue, "push", rb_queue_push, 1);
722
    rb_define_method(rb_cQueue, "pop", rb_queue_pop, -1);
723
    rb_define_method(rb_cQueue, "empty?", rb_queue_empty_p, 0);
724
    rb_define_method(rb_cQueue, "clear", rb_queue_clear, 0);
725
    rb_define_method(rb_cQueue, "length", rb_queue_length, 0);
726
    rb_define_method(rb_cQueue, "num_waiting", rb_queue_num_waiting, 0);
727
    rb_alias(rb_cQueue, rb_intern("enq"), rb_intern("push"));
728
    rb_alias(rb_cQueue, rb_intern("<<"), rb_intern("push"));
729
    rb_alias(rb_cQueue, rb_intern("deq"), rb_intern("pop"));
730
    rb_alias(rb_cQueue, rb_intern("shift"), rb_intern("pop"));
731
    rb_alias(rb_cQueue, rb_intern("size"), rb_intern("length"));
732

  
733
    rb_define_alloc_func(rb_cSizedQueue, szqueue_alloc);
734
    rb_define_method(rb_cSizedQueue, "initialize", rb_szqueue_initialize, 1);
735
    rb_define_method(rb_cSizedQueue, "max", rb_szqueue_max_get, 0);
736
    rb_define_method(rb_cSizedQueue, "max=", rb_szqueue_max_set, 1);
737
    rb_define_method(rb_cSizedQueue, "push", rb_szqueue_push, 1);
738
    rb_define_method(rb_cSizedQueue, "pop", rb_szqueue_pop, -1);
739
    rb_define_method(rb_cSizedQueue, "num_waiting", rb_szqueue_num_waiting, 0);
740
    rb_alias(rb_cSizedQueue, rb_intern("enq"), rb_intern("push"));
741
    rb_alias(rb_cSizedQueue, rb_intern("<<"), rb_intern("push"));
742
    rb_alias(rb_cSizedQueue, rb_intern("deq"), rb_intern("pop"));
743
    rb_alias(rb_cSizedQueue, rb_intern("shift"), rb_intern("pop"));
744

  
745
    rb_provide("thread.rb");
746
    ALIAS_GLOBCAL_CONST(ConditionVariable);
747
    ALIAS_GLOBCAL_CONST(Queue);
748
    ALIAS_GLOBCAL_CONST(SizedQueue);
749
}