fastthread 0.5.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rake/gempackagetask'
5
+ require 'tools/rakehelp'
6
+
7
+ GEM_VERSION="0.5.3.5"
8
+
9
+ setup_extension('fastthread', 'fastthread')
10
+
11
+ desc "Compiles native extensions"
12
+ task :compile => [:fastthread]
13
+
14
+ task :default => [:compile, :test]
15
+
16
+ Rake::TestTask.new do |task|
17
+ task.libs << 'test'
18
+ task.test_files = Dir.glob( 'test/test*.rb' )
19
+ task.verbose = true
20
+ end
21
+
22
+ gemspec = Gem::Specification.new do |gemspec|
23
+ gemspec.name = "fastthread"
24
+ gemspec.version = GEM_VERSION
25
+ gemspec.author = "MenTaLguY <mental@rydia.net>"
26
+ gemspec.summary = "Optimized replacement for thread.rb primitives"
27
+ gemspec.test_file = 'test/test_all.rb'
28
+ gemspec.files = %w( Rakefile setup.rb ) +
29
+ Dir.glob( 'test/*.rb' ) +
30
+ Dir.glob( 'ext/**/*.{c,rb}' ) +
31
+ Dir.glob( 'tools/*.rb' )
32
+
33
+ gemspec.require_path = 'lib'
34
+
35
+ if RUBY_PLATFORM.match("win32")
36
+ gemspec.platform = Gem::Platform::WIN32
37
+ gemspec.files += ['lib/fastthread.so']
38
+ else
39
+ gemspec.platform = Gem::Platform::RUBY
40
+ gemspec.extensions = Dir.glob( 'ext/**/extconf.rb' )
41
+ end
42
+ end
43
+
44
+ task :package => [:clean, :compile, :test]
45
+ Rake::GemPackageTask.new( gemspec ) do |task|
46
+ task.gem_spec = gemspec
47
+ task.need_tar = true
48
+ end
49
+
50
+ setup_clean ["ext/fastthread/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/fastthread/Makefile", "pkg", "lib/*.bundle", "*.gem", ".config"]
51
+
52
+ task :install => [:default] do
53
+ sh %{ sudo gem install pkg/fastthread-#{GEM_VERSION}.gem }
54
+ end
55
+
56
+ task :uninstall do
57
+ sh %{ sudo gem uninstall fastthread }
58
+ end
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile('fastthread')
@@ -0,0 +1,881 @@
1
+ /*
2
+ * Optimized Ruby Mutex implementation, loosely based on thread.rb by
3
+ * Yukihiro Matsumoto <matz@ruby-lang.org>
4
+ *
5
+ * Copyright 2006 MenTaLguY <mental@rydia.net>
6
+ *
7
+ * This file is made available under the same terms as Ruby.
8
+ */
9
+
10
+ #include <ruby.h>
11
+ #include <intern.h>
12
+ #include <rubysig.h>
13
+
14
+ static VALUE avoid_mem_pools;
15
+
16
+ #ifndef USE_MEM_POOLS
17
+ #define USE_MEM_POOLS !RTEST(avoid_mem_pools)
18
+ #endif
19
+
20
+ static ID mutex_ivar;
21
+
22
+ static VALUE rb_cMutex;
23
+ static VALUE rb_cConditionVariable;
24
+ /* post-1.8.5 Ruby exposes rb_eThreadError; earlier versions do not */
25
+ static VALUE private_eThreadError;
26
+ static VALUE rb_cQueue;
27
+ static VALUE rb_cSizedQueue;
28
+
29
+ static VALUE
30
+ return_value(value)
31
+ VALUE value;
32
+ {
33
+ return value;
34
+ }
35
+
36
+ typedef struct _Entry {
37
+ VALUE value;
38
+ struct _Entry *next;
39
+ } Entry;
40
+
41
+ typedef struct _List {
42
+ Entry *entries;
43
+ Entry *last_entry;
44
+ Entry *entry_pool;
45
+ unsigned long size;
46
+ } List;
47
+
48
+ static void
49
+ init_list(list)
50
+ List *list;
51
+ {
52
+ list->entries = NULL;
53
+ list->last_entry = NULL;
54
+ list->entry_pool = NULL;
55
+ list->size = 0;
56
+ }
57
+
58
+ static void
59
+ mark_list(list)
60
+ List *list;
61
+ {
62
+ Entry *entry;
63
+ for ( entry = list->entries ; entry ; entry = entry->next ) {
64
+ rb_gc_mark(entry->value);
65
+ }
66
+ }
67
+
68
+ static void
69
+ free_entries(first)
70
+ Entry *first;
71
+ {
72
+ Entry *next;
73
+ while (first) {
74
+ next = first->next;
75
+ free(first);
76
+ first = next;
77
+ }
78
+ }
79
+
80
+ static void
81
+ finalize_list(list)
82
+ List *list;
83
+ {
84
+ free_entries(list->entries);
85
+ free_entries(list->entry_pool);
86
+ }
87
+
88
+ static void
89
+ push_list(list, value)
90
+ List *list;
91
+ VALUE value;
92
+ {
93
+ Entry *entry;
94
+
95
+ if (list->entry_pool) {
96
+ entry = list->entry_pool;
97
+ list->entry_pool = entry->next;
98
+ } else {
99
+ entry = (Entry *)malloc(sizeof(Entry));
100
+ }
101
+
102
+ entry->value = value;
103
+ entry->next = NULL;
104
+
105
+ if (list->last_entry) {
106
+ list->last_entry->next = entry;
107
+ } else {
108
+ list->entries = entry;
109
+ }
110
+ list->last_entry = entry;
111
+
112
+ ++list->size;
113
+ }
114
+
115
+ static void
116
+ push_multiple_list(list, values, count)
117
+ List *list;
118
+ VALUE *values;
119
+ unsigned count;
120
+ {
121
+ unsigned i;
122
+ for ( i = 0 ; i < count ; i++ ) {
123
+ push_list(list, values[i]);
124
+ }
125
+ }
126
+
127
+ static VALUE
128
+ shift_list(list)
129
+ List *list;
130
+ {
131
+ Entry *entry;
132
+ VALUE value;
133
+
134
+ entry = list->entries;
135
+ if (!entry) return Qundef;
136
+
137
+ list->entries = entry->next;
138
+ if ( entry == list->last_entry ) {
139
+ list->last_entry = NULL;
140
+ }
141
+
142
+ --list->size;
143
+
144
+ value = entry->value;
145
+ if (USE_MEM_POOLS) {
146
+ entry->next = list->entry_pool;
147
+ list->entry_pool = entry;
148
+ } else {
149
+ free(entry);
150
+ }
151
+
152
+ return value;
153
+ }
154
+
155
+ static void
156
+ clear_list(list)
157
+ List *list;
158
+ {
159
+ if (list->last_entry) {
160
+ if (USE_MEM_POOLS) {
161
+ list->last_entry->next = list->entry_pool;
162
+ list->entry_pool = list->entries;
163
+ } else {
164
+ free_entries(list->entries);
165
+ }
166
+ list->entries = NULL;
167
+ list->last_entry = NULL;
168
+ list->size = 0;
169
+ }
170
+ }
171
+
172
+ static VALUE
173
+ array_from_list(list)
174
+ List const *list;
175
+ {
176
+ VALUE ary;
177
+ Entry *entry;
178
+ ary = rb_ary_new();
179
+ for ( entry = list->entries ; entry ; entry = entry->next ) {
180
+ rb_ary_push(ary, entry->value);
181
+ }
182
+ return ary;
183
+ }
184
+
185
+ static VALUE
186
+ wake_one(list)
187
+ List *list;
188
+ {
189
+ VALUE waking;
190
+
191
+ waking = Qnil;
192
+ while ( list->entries && !RTEST(waking) ) {
193
+ waking = rb_rescue2(rb_thread_wakeup, shift_list(list),
194
+ return_value, Qnil, private_eThreadError, 0);
195
+ }
196
+
197
+ return waking;
198
+ }
199
+
200
+ static VALUE
201
+ wake_all(list)
202
+ List *list;
203
+ {
204
+ while (list->entries) {
205
+ wake_one(list);
206
+ }
207
+ return Qnil;
208
+ }
209
+
210
+ typedef struct _Mutex {
211
+ VALUE owner;
212
+ List waiting;
213
+ } Mutex;
214
+
215
+ static void
216
+ mark_mutex(mutex)
217
+ Mutex *mutex;
218
+ {
219
+ rb_gc_mark(mutex->owner);
220
+ mark_list(&mutex->waiting);
221
+ }
222
+
223
+ static void
224
+ finalize_mutex(mutex)
225
+ Mutex *mutex;
226
+ {
227
+ finalize_list(&mutex->waiting);
228
+ }
229
+
230
+ static void
231
+ free_mutex(mutex)
232
+ Mutex *mutex;
233
+ {
234
+ if (mutex->waiting.entries) {
235
+ rb_bug("mutex %p freed with thread(s) waiting", mutex);
236
+ }
237
+ finalize_mutex(mutex);
238
+ free(mutex);
239
+ }
240
+
241
+ static void
242
+ init_mutex(mutex)
243
+ Mutex *mutex;
244
+ {
245
+ mutex->owner = Qnil;
246
+ init_list(&mutex->waiting);
247
+ }
248
+
249
+ static VALUE rb_mutex_alloc _((VALUE));
250
+
251
+ static VALUE
252
+ rb_mutex_alloc(klass)
253
+ VALUE klass;
254
+ {
255
+ Mutex *mutex;
256
+ mutex = (Mutex *)malloc(sizeof(Mutex));
257
+ init_mutex(mutex);
258
+ return Data_Wrap_Struct(klass, mark_mutex, free_mutex, mutex);
259
+ }
260
+
261
+ static VALUE
262
+ rb_mutex_locked_p(self)
263
+ VALUE self;
264
+ {
265
+ Mutex *mutex;
266
+ Data_Get_Struct(self, Mutex, mutex);
267
+ return ( RTEST(mutex->owner) ? Qtrue : Qfalse );
268
+ }
269
+
270
+ static VALUE
271
+ rb_mutex_try_lock(self)
272
+ VALUE self;
273
+ {
274
+ Mutex *mutex;
275
+ VALUE result;
276
+
277
+ Data_Get_Struct(self, Mutex, mutex);
278
+
279
+ result = Qfalse;
280
+
281
+ rb_thread_critical = 1;
282
+ if (!RTEST(mutex->owner)) {
283
+ mutex->owner = rb_thread_current();
284
+ result = Qtrue;
285
+ }
286
+ rb_thread_critical = 0;
287
+
288
+ return result;
289
+ }
290
+
291
+ static void
292
+ lock_mutex(mutex)
293
+ Mutex *mutex;
294
+ {
295
+ VALUE current;
296
+ current = rb_thread_current();
297
+
298
+ rb_thread_critical = 1;
299
+
300
+ while (RTEST(mutex->owner)) {
301
+ push_list(&mutex->waiting, current);
302
+ rb_thread_stop();
303
+
304
+ rb_thread_critical = 1;
305
+ }
306
+ mutex->owner = current;
307
+
308
+ rb_thread_critical = 0;
309
+ }
310
+
311
+ static VALUE
312
+ rb_mutex_lock(self)
313
+ VALUE self;
314
+ {
315
+ Mutex *mutex;
316
+ Data_Get_Struct(self, Mutex, mutex);
317
+ lock_mutex(mutex);
318
+ return self;
319
+ }
320
+
321
+ static VALUE
322
+ unlock_mutex_inner(mutex)
323
+ Mutex *mutex;
324
+ {
325
+ VALUE waking;
326
+
327
+ if (!RTEST(mutex->owner)) {
328
+ return Qundef;
329
+ }
330
+ mutex->owner = Qnil;
331
+ waking = wake_one(&mutex->waiting);
332
+
333
+ return waking;
334
+ }
335
+
336
+ static VALUE
337
+ set_critical(value)
338
+ VALUE value;
339
+ {
340
+ rb_thread_critical = (int)value;
341
+ return Qnil;
342
+ }
343
+
344
+ static VALUE
345
+ unlock_mutex(mutex)
346
+ Mutex *mutex;
347
+ {
348
+ VALUE waking;
349
+
350
+ rb_thread_critical = 1;
351
+ waking = rb_ensure(unlock_mutex_inner, (VALUE)mutex, set_critical, 0);
352
+
353
+ if ( waking == Qundef ) {
354
+ return Qfalse;
355
+ }
356
+
357
+ if (RTEST(waking)) {
358
+ rb_rescue2(rb_thread_run, waking, return_value, Qnil, private_eThreadError, 0);
359
+ }
360
+
361
+ return Qtrue;
362
+ }
363
+
364
+ static VALUE
365
+ rb_mutex_unlock(self)
366
+ VALUE self;
367
+ {
368
+ Mutex *mutex;
369
+ Data_Get_Struct(self, Mutex, mutex);
370
+
371
+ if (RTEST(unlock_mutex(mutex))) {
372
+ return self;
373
+ } else {
374
+ return Qnil;
375
+ }
376
+ }
377
+
378
+ static VALUE
379
+ rb_mutex_exclusive_unlock_inner(mutex)
380
+ Mutex *mutex;
381
+ {
382
+ VALUE waking;
383
+ waking = unlock_mutex_inner(mutex);
384
+ rb_yield(Qundef);
385
+ return waking;
386
+ }
387
+
388
+ static VALUE
389
+ rb_mutex_exclusive_unlock(self)
390
+ VALUE self;
391
+ {
392
+ Mutex *mutex;
393
+ VALUE waking;
394
+ Data_Get_Struct(self, Mutex, mutex);
395
+
396
+ rb_thread_critical = 1;
397
+ waking = rb_ensure(rb_mutex_exclusive_unlock_inner, (VALUE)mutex, set_critical, 0);
398
+
399
+ if ( waking == Qundef ) {
400
+ return Qnil;
401
+ }
402
+
403
+ if (RTEST(waking)) {
404
+ rb_rescue2(rb_thread_run, waking, return_value, Qnil, private_eThreadError, 0);
405
+ }
406
+
407
+ return self;
408
+ }
409
+
410
+ static VALUE
411
+ rb_mutex_synchronize(self)
412
+ VALUE self;
413
+ {
414
+ rb_mutex_lock(self);
415
+ return rb_ensure(rb_yield, Qundef, rb_mutex_unlock, self);
416
+ }
417
+
418
+ typedef struct _ConditionVariable {
419
+ List waiting;
420
+ } ConditionVariable;
421
+
422
+ static void
423
+ mark_condvar(condvar)
424
+ ConditionVariable *condvar;
425
+ {
426
+ mark_list(&condvar->waiting);
427
+ }
428
+
429
+ static void
430
+ finalize_condvar(condvar)
431
+ ConditionVariable *condvar;
432
+ {
433
+ finalize_list(&condvar->waiting);
434
+ }
435
+
436
+ static void
437
+ free_condvar(condvar)
438
+ ConditionVariable *condvar;
439
+ {
440
+ finalize_condvar(condvar);
441
+ free(condvar);
442
+ }
443
+
444
+ static void
445
+ init_condvar(condvar)
446
+ ConditionVariable *condvar;
447
+ {
448
+ init_list(&condvar->waiting);
449
+ }
450
+
451
+ static VALUE rb_condvar_alloc _((VALUE));
452
+
453
+ static VALUE
454
+ rb_condvar_alloc(klass)
455
+ VALUE klass;
456
+ {
457
+ ConditionVariable *condvar;
458
+
459
+ condvar = (ConditionVariable *)malloc(sizeof(ConditionVariable));
460
+ init_condvar(condvar);
461
+
462
+ return Data_Wrap_Struct(klass, mark_condvar, free_condvar, condvar);
463
+ }
464
+
465
+ static void
466
+ wait_condvar(condvar, mutex)
467
+ ConditionVariable *condvar;
468
+ Mutex *mutex;
469
+ {
470
+ rb_thread_critical = 1;
471
+ if (!RTEST(mutex->owner)) {
472
+ rb_thread_critical = Qfalse;
473
+ return;
474
+ }
475
+ if ( mutex->owner != rb_thread_current() ) {
476
+ rb_thread_critical = Qfalse;
477
+ rb_raise(private_eThreadError, "Not owner");
478
+ }
479
+ mutex->owner = Qnil;
480
+ push_list(&condvar->waiting, rb_thread_current());
481
+ rb_thread_stop();
482
+
483
+ lock_mutex(mutex);
484
+ }
485
+
486
+ static VALUE
487
+ rb_condvar_wait(VALUE self, VALUE mutex_v)
488
+ {
489
+ ConditionVariable *condvar;
490
+ Mutex *mutex;
491
+
492
+ if ( CLASS_OF(mutex_v) != rb_cMutex ) {
493
+ rb_raise(rb_eTypeError, "Not a Mutex");
494
+ }
495
+ Data_Get_Struct(self, ConditionVariable, condvar);
496
+ Data_Get_Struct(mutex_v, Mutex, mutex);
497
+
498
+ wait_condvar(condvar, mutex);
499
+
500
+ return self;
501
+ }
502
+
503
+ static VALUE
504
+ rb_condvar_broadcast(self)
505
+ VALUE self;
506
+ {
507
+ ConditionVariable *condvar;
508
+
509
+ Data_Get_Struct(self, ConditionVariable, condvar);
510
+
511
+ rb_thread_critical = 1;
512
+ rb_ensure(wake_all, (VALUE)&condvar->waiting, set_critical, 0);
513
+ rb_thread_schedule();
514
+
515
+ return self;
516
+ }
517
+
518
+ static void
519
+ signal_condvar(condvar)
520
+ ConditionVariable *condvar;
521
+ {
522
+ VALUE waking;
523
+ rb_thread_critical = 1;
524
+ waking = rb_ensure(wake_one, (VALUE)&condvar->waiting, set_critical, 0);
525
+ if (RTEST(waking)) {
526
+ rb_rescue2(rb_thread_run, waking, return_value, Qnil, private_eThreadError, 0);
527
+ }
528
+ }
529
+
530
+ static VALUE
531
+ rb_condvar_signal(self)
532
+ VALUE self;
533
+ {
534
+ ConditionVariable *condvar;
535
+ Data_Get_Struct(self, ConditionVariable, condvar);
536
+ signal_condvar(condvar);
537
+ return self;
538
+ }
539
+
540
+ typedef struct _Queue {
541
+ Mutex mutex;
542
+ ConditionVariable value_available;
543
+ ConditionVariable space_available;
544
+ List values;
545
+ unsigned long capacity;
546
+ } Queue;
547
+
548
+ static void
549
+ mark_queue(queue)
550
+ Queue *queue;
551
+ {
552
+ mark_mutex(&queue->mutex);
553
+ mark_condvar(&queue->value_available);
554
+ mark_condvar(&queue->space_available);
555
+ mark_list(&queue->values);
556
+ }
557
+
558
+ static void
559
+ finalize_queue(queue)
560
+ Queue *queue;
561
+ {
562
+ finalize_mutex(&queue->mutex);
563
+ finalize_condvar(&queue->value_available);
564
+ finalize_condvar(&queue->space_available);
565
+ finalize_list(&queue->values);
566
+ }
567
+
568
+ static void
569
+ free_queue(queue)
570
+ Queue *queue;
571
+ {
572
+ finalize_queue(queue);
573
+ free(queue);
574
+ }
575
+
576
+ static void
577
+ init_queue(queue)
578
+ Queue *queue;
579
+ {
580
+ init_mutex(&queue->mutex);
581
+ init_condvar(&queue->value_available);
582
+ init_condvar(&queue->space_available);
583
+ init_list(&queue->values);
584
+ queue->capacity = 0;
585
+ }
586
+
587
+ static VALUE rb_queue_alloc _((VALUE));
588
+
589
+ static VALUE
590
+ rb_queue_alloc(klass)
591
+ VALUE klass;
592
+ {
593
+ Queue *queue;
594
+ queue = (Queue *)malloc(sizeof(Queue));
595
+ init_queue(queue);
596
+ return Data_Wrap_Struct(klass, mark_queue, free_queue, queue);
597
+ }
598
+
599
+ static VALUE
600
+ rb_queue_marshal_load(self, data)
601
+ VALUE self;
602
+ VALUE data;
603
+ {
604
+ Queue *queue;
605
+ VALUE array;
606
+ Data_Get_Struct(self, Queue, queue);
607
+
608
+ array = rb_marshal_load(data);
609
+ if ( TYPE(array) != T_ARRAY ) {
610
+ rb_raise(rb_eRuntimeError, "expected Array of queue data");
611
+ }
612
+ if ( RARRAY(array)->len < 1 ) {
613
+ rb_raise(rb_eRuntimeError, "missing capacity value");
614
+ }
615
+ queue->capacity = NUM2ULONG(rb_ary_shift(array));
616
+ push_multiple_list(&queue->values, RARRAY(array)->ptr, (unsigned)RARRAY(array)->len);
617
+
618
+ return self;
619
+ }
620
+
621
+ static VALUE
622
+ rb_queue_marshal_dump(self)
623
+ VALUE self;
624
+ {
625
+ Queue *queue;
626
+ VALUE array;
627
+ Data_Get_Struct(self, Queue, queue);
628
+
629
+ array = array_from_list(&queue->values);
630
+ rb_ary_unshift(array, ULONG2NUM(queue->capacity));
631
+ return rb_marshal_dump(array, Qnil);
632
+ }
633
+
634
+ static VALUE
635
+ rb_queue_clear(self)
636
+ VALUE self;
637
+ {
638
+ Queue *queue;
639
+ Data_Get_Struct(self, Queue, queue);
640
+
641
+ lock_mutex(&queue->mutex);
642
+ clear_list(&queue->values);
643
+ signal_condvar(&queue->space_available);
644
+ unlock_mutex(&queue->mutex);
645
+
646
+ return self;
647
+ }
648
+
649
+ static VALUE
650
+ rb_queue_empty_p(self)
651
+ VALUE self;
652
+ {
653
+ Queue *queue;
654
+ VALUE result;
655
+ Data_Get_Struct(self, Queue, queue);
656
+
657
+ lock_mutex(&queue->mutex);
658
+ result = ( ( queue->values.size == 0 ) ? Qtrue : Qfalse );
659
+ unlock_mutex(&queue->mutex);
660
+
661
+ return result;
662
+ }
663
+
664
+ static VALUE
665
+ rb_queue_length(self)
666
+ VALUE self;
667
+ {
668
+ Queue *queue;
669
+ VALUE result;
670
+ Data_Get_Struct(self, Queue, queue);
671
+
672
+ lock_mutex(&queue->mutex);
673
+ result = ULONG2NUM(queue->values.size);
674
+ unlock_mutex(&queue->mutex);
675
+
676
+ return result;
677
+ }
678
+
679
+ static VALUE
680
+ rb_queue_num_waiting(self)
681
+ VALUE self;
682
+ {
683
+ Queue *queue;
684
+ VALUE result;
685
+ Data_Get_Struct(self, Queue, queue);
686
+
687
+ lock_mutex(&queue->mutex);
688
+ result = ULONG2NUM(queue->value_available.waiting.size +
689
+ queue->space_available.waiting.size);
690
+ unlock_mutex(&queue->mutex);
691
+
692
+ return result;
693
+ }
694
+
695
+ static VALUE
696
+ rb_queue_pop(argc, argv, self)
697
+ int argc;
698
+ VALUE *argv;
699
+ VALUE self;
700
+ {
701
+ Queue *queue;
702
+ int should_block;
703
+ VALUE result;
704
+ Data_Get_Struct(self, Queue, queue);
705
+
706
+ if ( argc == 0 ) {
707
+ should_block = 1;
708
+ } else if ( argc == 1 ) {
709
+ should_block = !RTEST(argv[0]);
710
+ } else {
711
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
712
+ }
713
+
714
+ lock_mutex(&queue->mutex);
715
+ if ( !queue->values.entries && !should_block ) {
716
+ unlock_mutex(&queue->mutex);
717
+ rb_raise(private_eThreadError, "queue empty");
718
+ }
719
+
720
+ while (!queue->values.entries) {
721
+ wait_condvar(&queue->value_available, &queue->mutex);
722
+ }
723
+
724
+ result = shift_list(&queue->values);
725
+ if ( queue->capacity && queue->values.size < queue->capacity ) {
726
+ signal_condvar(&queue->space_available);
727
+ }
728
+ unlock_mutex(&queue->mutex);
729
+
730
+ return result;
731
+ }
732
+
733
+ static VALUE
734
+ rb_queue_push(self, value)
735
+ VALUE self;
736
+ VALUE value;
737
+ {
738
+ Queue *queue;
739
+ Data_Get_Struct(self, Queue, queue);
740
+
741
+ lock_mutex(&queue->mutex);
742
+ while ( queue->capacity && queue->values.size >= queue->capacity ) {
743
+ wait_condvar(&queue->space_available, &queue->mutex);
744
+ }
745
+ push_list(&queue->values, value);
746
+ signal_condvar(&queue->value_available);
747
+ unlock_mutex(&queue->mutex);
748
+
749
+ return self;
750
+ }
751
+
752
+ static VALUE
753
+ rb_sized_queue_max(self)
754
+ VALUE self;
755
+ {
756
+ Queue *queue;
757
+ VALUE result;
758
+ Data_Get_Struct(self, Queue, queue);
759
+
760
+ lock_mutex(&queue->mutex);
761
+ result = ULONG2NUM(queue->capacity);
762
+ unlock_mutex(&queue->mutex);
763
+
764
+ return result;
765
+ }
766
+
767
+ static VALUE
768
+ rb_sized_queue_max_set(self, value)
769
+ VALUE self;
770
+ VALUE value;
771
+ {
772
+ Queue *queue;
773
+ unsigned long new_capacity;
774
+ unsigned long difference;
775
+ Data_Get_Struct(self, Queue, queue);
776
+
777
+ new_capacity = NUM2ULONG(value);
778
+
779
+ if ( new_capacity < 1 ) {
780
+ rb_raise(rb_eArgError, "value must be positive");
781
+ }
782
+
783
+ lock_mutex(&queue->mutex);
784
+ if ( queue->capacity && new_capacity > queue->capacity ) {
785
+ difference = new_capacity - queue->capacity;
786
+ } else {
787
+ difference = 0;
788
+ }
789
+ queue->capacity = new_capacity;
790
+ for ( ; difference > 0 ; --difference ) {
791
+ signal_condvar(&queue->space_available);
792
+ }
793
+ unlock_mutex(&queue->mutex);
794
+
795
+ return self;
796
+ }
797
+
798
+ /* Existing code expects to be able to serialize Mutexes... */
799
+
800
+ static VALUE
801
+ dummy_load(self, string)
802
+ VALUE self;
803
+ VALUE string;
804
+ {
805
+ return Qnil;
806
+ }
807
+
808
+ static VALUE
809
+ dummy_dump(self)
810
+ VALUE self;
811
+ {
812
+ return rb_str_new2("");
813
+ }
814
+
815
+ void
816
+ Init_fastthread()
817
+ {
818
+ avoid_mem_pools = rb_gv_get("$fastthread_avoid_mem_pools");
819
+ rb_global_variable(&avoid_mem_pools);
820
+ rb_define_variable("$fastthread_avoid_mem_pools", &avoid_mem_pools);
821
+
822
+ mutex_ivar = rb_intern("__mutex__");
823
+
824
+ if (!RTEST(rb_require("thread"))) {
825
+ rb_raise(rb_eRuntimeError, "fastthread must be required before thread");
826
+ }
827
+
828
+ private_eThreadError = rb_const_get(rb_cObject, rb_intern("ThreadError"));
829
+
830
+ rb_cMutex = rb_define_class("Mutex", rb_cObject);
831
+ rb_define_alloc_func(rb_cMutex, rb_mutex_alloc);
832
+ rb_define_method(rb_cMutex, "marshal_load", dummy_load, 1);
833
+ rb_define_method(rb_cMutex, "marshal_dump", dummy_dump, 0);
834
+ rb_define_method(rb_cMutex, "initialize", return_value, 0);
835
+ rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
836
+ rb_define_method(rb_cMutex, "try_lock", rb_mutex_try_lock, 0);
837
+ rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
838
+ rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
839
+ rb_define_method(rb_cMutex, "exclusive_unlock", rb_mutex_exclusive_unlock, 0);
840
+ rb_define_method(rb_cMutex, "synchronize", rb_mutex_synchronize, 0);
841
+
842
+ rb_cConditionVariable = rb_define_class("ConditionVariable", rb_cObject);
843
+ rb_define_alloc_func(rb_cConditionVariable, rb_condvar_alloc);
844
+ rb_define_method(rb_cConditionVariable, "marshal_load", dummy_load, 1);
845
+ rb_define_method(rb_cConditionVariable, "marshal_dump", dummy_dump, 0);
846
+ rb_define_method(rb_cConditionVariable, "initialize", return_value, 0);
847
+ rb_define_method(rb_cConditionVariable, "wait", rb_condvar_wait, 1);
848
+ rb_define_method(rb_cConditionVariable, "broadcast", rb_condvar_broadcast, 0);
849
+ rb_define_method(rb_cConditionVariable, "signal", rb_condvar_signal, 0);
850
+
851
+ rb_cQueue = rb_define_class("Queue", rb_cObject);
852
+ rb_define_alloc_func(rb_cQueue, rb_queue_alloc);
853
+ rb_define_method(rb_cQueue, "marshal_load", rb_queue_marshal_load, 1);
854
+ rb_define_method(rb_cQueue, "marshal_dump", rb_queue_marshal_dump, 0);
855
+ rb_define_method(rb_cQueue, "initialize", return_value, 0);
856
+ rb_define_method(rb_cQueue, "clear", rb_queue_clear, 0);
857
+ rb_define_method(rb_cQueue, "empty?", rb_queue_empty_p, 0);
858
+ rb_define_method(rb_cQueue, "length", rb_queue_length, 0);
859
+ rb_define_method(rb_cQueue, "num_waiting", rb_queue_num_waiting, 0);
860
+ rb_define_method(rb_cQueue, "pop", rb_queue_pop, -1);
861
+ rb_define_method(rb_cQueue, "push", rb_queue_push, 1);
862
+ rb_alias(rb_cQueue, rb_intern("<<"), rb_intern("push"));
863
+ rb_alias(rb_cQueue, rb_intern("deq"), rb_intern("pop"));
864
+ rb_alias(rb_cQueue, rb_intern("shift"), rb_intern("pop"));
865
+ rb_alias(rb_cQueue, rb_intern("size"), rb_intern("length"));
866
+
867
+ rb_cSizedQueue = rb_define_class("SizedQueue", rb_cQueue);
868
+ rb_define_method(rb_cSizedQueue, "initialize", rb_sized_queue_max_set, 1);
869
+ rb_define_method(rb_cSizedQueue, "clear", rb_queue_clear, 0);
870
+ rb_define_method(rb_cSizedQueue, "empty?", rb_queue_empty_p, 0);
871
+ rb_define_method(rb_cSizedQueue, "length", rb_queue_length, 0);
872
+ rb_define_method(rb_cSizedQueue, "num_waiting", rb_queue_num_waiting, 0);
873
+ rb_define_method(rb_cSizedQueue, "pop", rb_queue_pop, -1);
874
+ rb_define_method(rb_cSizedQueue, "push", rb_queue_push, 1);
875
+ rb_define_method(rb_cSizedQueue, "max", rb_sized_queue_max, 0);
876
+ rb_define_method(rb_cSizedQueue, "max=", rb_sized_queue_max_set, 1);
877
+ rb_alias(rb_cSizedQueue, rb_intern("<<"), rb_intern("push"));
878
+ rb_alias(rb_cSizedQueue, rb_intern("deq"), rb_intern("pop"));
879
+ rb_alias(rb_cSizedQueue, rb_intern("shift"), rb_intern("pop"));
880
+ }
881
+