Skip to content

Commit 512180c

Browse files
committed
Restored original experimental CAtomicBoolean.
1 parent ac140b1 commit 512180c

File tree

7 files changed

+377
-2
lines changed

7 files changed

+377
-2
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#include <ruby.h>
2+
#include <stdbool.h>
3+
4+
#include "atomic_boolean.h"
5+
6+
void Check_Boolean(VALUE value) {
7+
VALUE type = TYPE(value);
8+
9+
if (type != T_TRUE && type != T_FALSE) {
10+
rb_raise(rb_eTypeError, "must be a boolean");
11+
}
12+
}
13+
14+
// http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/_005f_005fatomic-Builtins.html
15+
16+
VALUE atomic_boolean_allocate(VALUE klass) {
17+
CAtomicBoolean* atomic;
18+
VALUE sval = Data_Make_Struct(klass, CAtomicBoolean, NULL, atomic_boolean_deallocate, atomic);
19+
20+
#ifndef __USE_GCC_ATOMIC
21+
pthread_mutex_init(&atomic->mutex, NULL);
22+
#endif
23+
24+
return(sval);
25+
}
26+
27+
void atomic_boolean_deallocate(void* sval) {
28+
CAtomicBoolean* atomic = (CAtomicBoolean*) sval;
29+
30+
#ifndef __USE_GCC_ATOMIC
31+
pthread_mutex_destroy(&atomic->mutex);
32+
#endif
33+
34+
free(atomic);
35+
}
36+
37+
VALUE method_atomic_boolean_initialize(int argc, VALUE* argv, VALUE self) {
38+
CAtomicBoolean* atomic;
39+
40+
rb_check_arity(argc, 0, 1);
41+
42+
Data_Get_Struct(self, CAtomicBoolean, atomic);
43+
44+
atomic->value = (argc == 1 ? RUBY2BOOL(argv[0]) : Qfalse);
45+
return(self);
46+
}
47+
48+
VALUE method_atomic_boolean_value(VALUE self) {
49+
CAtomicBoolean* atomic;
50+
bool value;
51+
52+
Data_Get_Struct(self, CAtomicBoolean, atomic);
53+
54+
#ifdef __USE_GCC_ATOMIC
55+
value = __atomic_load_n(&atomic->value, __ATOMIC_SEQ_CST);
56+
#else
57+
pthread_mutex_lock(&atomic->mutex);
58+
value = atomic->value;
59+
pthread_mutex_unlock(&atomic->mutex);
60+
#endif
61+
62+
return BOOL2RUBY(value);
63+
}
64+
65+
VALUE method_atomic_boolean_value_set(VALUE self, VALUE value) {
66+
CAtomicBoolean* atomic;
67+
bool new_value;
68+
69+
new_value = RUBY2BOOL(value);
70+
Data_Get_Struct(self, CAtomicBoolean, atomic);
71+
72+
#ifdef __USE_GCC_ATOMIC
73+
__atomic_store_n(&atomic->value, new_value, __ATOMIC_SEQ_CST);
74+
#else
75+
pthread_mutex_lock(&atomic->mutex);
76+
atomic->value = new_value;
77+
pthread_mutex_unlock(&atomic->mutex);
78+
#endif
79+
80+
return(value);
81+
}
82+
83+
VALUE method_atomic_boolean_true_question(VALUE self) {
84+
return(method_atomic_boolean_value(self));
85+
}
86+
87+
VALUE method_atomic_boolean_false_question(VALUE self) {
88+
VALUE current = method_atomic_boolean_value(self);
89+
return(BOOL2RUBY(current == Qfalse));
90+
}
91+
92+
VALUE method_atomic_boolean_make_true(VALUE self) {
93+
CAtomicBoolean* atomic;
94+
bool value = false;
95+
#ifdef __USE_GCC_ATOMIC
96+
bool expected = false;
97+
#endif
98+
99+
Data_Get_Struct(self, CAtomicBoolean, atomic);
100+
101+
#ifdef __USE_GCC_ATOMIC
102+
value = __atomic_compare_exchange_n(&atomic->value, &expected, true, false,
103+
__ATOMIC_RELEASE, __ATOMIC_SEQ_CST);
104+
#else
105+
pthread_mutex_lock(&atomic->mutex);
106+
if (! atomic->value) {
107+
atomic->value = Qtrue;
108+
value = true;
109+
}
110+
pthread_mutex_unlock(&atomic->mutex);
111+
#endif
112+
113+
return(BOOL2RUBY(value));
114+
}
115+
116+
VALUE method_atomic_boolean_make_false(VALUE self) {
117+
CAtomicBoolean* atomic;
118+
bool value = false;
119+
#ifdef __USE_GCC_ATOMIC
120+
bool expected = true;
121+
#endif
122+
123+
Data_Get_Struct(self, CAtomicBoolean, atomic);
124+
125+
#ifdef __USE_GCC_ATOMIC
126+
value = __atomic_compare_exchange_n(&atomic->value, &expected, false, false,
127+
__ATOMIC_RELEASE, __ATOMIC_SEQ_CST);
128+
#else
129+
pthread_mutex_lock(&atomic->mutex);
130+
if (atomic->value) {
131+
atomic->value = Qfalse;
132+
value = true;
133+
}
134+
pthread_mutex_unlock(&atomic->mutex);
135+
#endif
136+
137+
return(BOOL2RUBY(value));
138+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef __ATOMIC_BOOLEAN_H__
2+
#define __ATOMIC_BOOLEAN_H__
3+
4+
#ifdef __ATOMIC_SEQ_CST
5+
#define __USE_GCC_ATOMIC
6+
#endif
7+
8+
#ifndef __USE_GCC_ATOMIC
9+
#include <pthread.h>
10+
#endif
11+
12+
#include <stdbool.h>
13+
14+
#define RUBY2BOOL(value)(! (value == Qfalse || value == Qnil))
15+
#define BOOL2RUBY(value)(value == true ? Qtrue : Qfalse)
16+
17+
typedef struct atomic_boolean {
18+
bool value;
19+
#ifndef __USE_GCC_ATOMIC
20+
pthread_mutex_t mutex;
21+
#endif
22+
} CAtomicBoolean;
23+
24+
void Check_Boolean(VALUE);
25+
26+
VALUE atomic_boolean_allocate(VALUE);
27+
void atomic_boolean_deallocate(void*);
28+
VALUE method_atomic_boolean_initialize(int, VALUE*, VALUE);
29+
VALUE method_atomic_boolean_value(VALUE);
30+
VALUE method_atomic_boolean_value_set(VALUE, VALUE);
31+
VALUE method_atomic_boolean_true_question(VALUE);
32+
VALUE method_atomic_boolean_false_question(VALUE);
33+
VALUE method_atomic_boolean_make_true(VALUE);
34+
VALUE method_atomic_boolean_make_false(VALUE);
35+
36+
#endif
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#include <ruby.h>
2+
#include <stdbool.h>
3+
4+
#include "atomic_fixnum.h"
5+
6+
// http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/_005f_005fatomic-Builtins.html
7+
8+
VALUE atomic_fixnum_allocate(VALUE klass) {
9+
CAtomicFixnum* atomic;
10+
VALUE sval = Data_Make_Struct(klass, CAtomicFixnum, NULL, atomic_fixnum_deallocate, atomic);
11+
12+
#ifndef __USE_GCC_ATOMIC
13+
pthread_mutex_init(&atomic->mutex, NULL);
14+
#endif
15+
16+
return(sval);
17+
}
18+
19+
void atomic_fixnum_deallocate(void* sval) {
20+
CAtomicFixnum* atomic = (CAtomicFixnum*) sval;
21+
22+
#ifndef __USE_GCC_ATOMIC
23+
pthread_mutex_destroy(&atomic->mutex);
24+
#endif
25+
26+
free(atomic);
27+
}
28+
29+
VALUE method_atomic_fixnum_initialize(int argc, VALUE* argv, VALUE self) {
30+
CAtomicFixnum* atomic;
31+
32+
rb_check_arity(argc, 0, 1);
33+
if (argc == 1) Check_Type(argv[0], T_FIXNUM);
34+
35+
Data_Get_Struct(self, CAtomicFixnum, atomic);
36+
37+
atomic->value = (argc == 1 ? FIX2INT(argv[0]) : 0);
38+
return(self);
39+
}
40+
41+
VALUE method_atomic_fixnum_value(VALUE self) {
42+
CAtomicFixnum* atomic;
43+
long value;
44+
45+
Data_Get_Struct(self, CAtomicFixnum, atomic);
46+
47+
#ifdef __USE_GCC_ATOMIC
48+
value = __atomic_load_n(&atomic->value, __ATOMIC_SEQ_CST);
49+
#else
50+
pthread_mutex_lock(&atomic->mutex);
51+
value = atomic->value;
52+
pthread_mutex_unlock(&atomic->mutex);
53+
#endif
54+
55+
return INT2FIX(value);
56+
}
57+
58+
VALUE method_atomic_fixnum_value_set(VALUE self, VALUE value) {
59+
CAtomicFixnum* atomic;
60+
long new_value;
61+
62+
Check_Type(value, T_FIXNUM);
63+
64+
new_value = FIX2INT(value);
65+
Data_Get_Struct(self, CAtomicFixnum, atomic);
66+
67+
#ifdef __USE_GCC_ATOMIC
68+
__atomic_store_n(&atomic->value, new_value, __ATOMIC_SEQ_CST);
69+
#else
70+
pthread_mutex_lock(&atomic->mutex);
71+
atomic->value = new_value;
72+
pthread_mutex_unlock(&atomic->mutex);
73+
#endif
74+
75+
return(value);
76+
}
77+
78+
VALUE method_atomic_fixnum_increment(VALUE self) {
79+
CAtomicFixnum* atomic;
80+
long value;
81+
82+
Data_Get_Struct(self, CAtomicFixnum, atomic);
83+
value = ++atomic->value;
84+
85+
return(INT2FIX(value));
86+
}
87+
88+
VALUE method_atomic_fixnum_decrement(VALUE self) {
89+
CAtomicFixnum* atomic;
90+
long value;
91+
92+
Data_Get_Struct(self, CAtomicFixnum, atomic);
93+
value = --atomic->value;
94+
95+
return(INT2FIX(value));
96+
}
97+
98+
VALUE method_atomic_fixnum_compare_and_set(VALUE self, VALUE rb_expect, VALUE rb_update) {
99+
CAtomicFixnum* atomic;
100+
long expect, update;
101+
102+
#ifdef __USE_GCC_ATOMIC
103+
VALUE value;
104+
#else
105+
VALUE value = Qfalse;
106+
#endif
107+
108+
Check_Type(rb_expect, T_FIXNUM);
109+
Check_Type(rb_update, T_FIXNUM);
110+
111+
Data_Get_Struct(self, CAtomicFixnum, atomic);
112+
113+
expect = FIX2INT(rb_expect);
114+
update = FIX2INT(rb_update);
115+
116+
#ifdef __USE_GCC_ATOMIC
117+
value = __atomic_compare_exchange_n(&atomic->value, &expect, update, false,
118+
__ATOMIC_RELEASE, __ATOMIC_SEQ_CST) ? Qtrue : Qfalse;
119+
#else
120+
pthread_mutex_lock(&atomic->mutex);
121+
if (atomic->value == expect) {
122+
atomic->value = update;
123+
value = Qtrue;
124+
}
125+
pthread_mutex_unlock(&atomic->mutex);
126+
#endif
127+
128+
return(value);
129+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#ifndef __ATOMIC_FIXNUM_H__
2+
#define __ATOMIC_FIXNUM_H__
3+
4+
#ifdef __ATOMIC_SEQ_CST
5+
#define __USE_GCC_ATOMIC
6+
#endif
7+
8+
#ifndef __USE_GCC_ATOMIC
9+
#include <pthread.h>
10+
#endif
11+
12+
typedef struct atomic_fixnum {
13+
long value;
14+
#ifndef __USE_GCC_ATOMIC
15+
pthread_mutex_t mutex;
16+
#endif
17+
} CAtomicFixnum;
18+
19+
VALUE atomic_fixnum_allocate(VALUE);
20+
void atomic_fixnum_deallocate(void*);
21+
VALUE method_atomic_fixnum_initialize(int, VALUE*, VALUE);
22+
VALUE method_atomic_fixnum_value(VALUE);
23+
VALUE method_atomic_fixnum_value_set(VALUE, VALUE);
24+
VALUE method_atomic_fixnum_increment(VALUE);
25+
VALUE method_atomic_fixnum_decrement(VALUE);
26+
VALUE method_atomic_fixnum_compare_and_set(VALUE, VALUE, VALUE);
27+
28+
#endif

ext/concurrent_ruby_ext/rb_concurrent.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
#include <ruby.h>
22

33
#include "atomic_reference.h"
4+
#include "atomic_boolean.h"
5+
#include "atomic_fixnum.h"
46

57
// module and class definitions
68

79
static VALUE rb_mConcurrent;
810
static VALUE rb_cAtomic;
11+
static VALUE rb_cAtomicBoolean;
12+
static VALUE rb_cAtomicFixnum;
913

1014
// Init_concurrent_ruby_ext
1115

@@ -14,6 +18,8 @@ void Init_concurrent_ruby_ext() {
1418
// define modules and classes
1519
rb_mConcurrent = rb_define_module("Concurrent");
1620
rb_cAtomic = rb_define_class_under(rb_mConcurrent, "CAtomic", rb_cObject);
21+
rb_cAtomicBoolean = rb_define_class_under(rb_mConcurrent, "CAtomicBoolean", rb_cObject);
22+
rb_cAtomicFixnum = rb_define_class_under(rb_mConcurrent, "CAtomicFixnum", rb_cObject);
1723

1824
// CAtomic
1925
rb_define_alloc_func(rb_cAtomic, ir_alloc);
@@ -25,4 +31,25 @@ void Init_concurrent_ruby_ext() {
2531
rb_define_method(rb_cAtomic, "get_and_set", ir_get_and_set, 1);
2632
rb_define_method(rb_cAtomic, "swap", ir_get_and_set, 1);
2733
rb_define_method(rb_cAtomic, "_compare_and_set", ir_compare_and_set, 2);
34+
35+
// CAtomicBoolean
36+
rb_define_alloc_func(rb_cAtomicBoolean, atomic_boolean_allocate);
37+
rb_define_method(rb_cAtomicBoolean, "initialize", method_atomic_boolean_initialize, -1);
38+
rb_define_method(rb_cAtomicBoolean, "value", method_atomic_boolean_value, 0);
39+
rb_define_method(rb_cAtomicBoolean, "value=", method_atomic_boolean_value_set, 1);
40+
rb_define_method(rb_cAtomicBoolean, "true?", method_atomic_boolean_true_question, 0);
41+
rb_define_method(rb_cAtomicBoolean, "false?", method_atomic_boolean_false_question, 0);
42+
rb_define_method(rb_cAtomicBoolean, "make_true", method_atomic_boolean_make_true, 0);
43+
rb_define_method(rb_cAtomicBoolean, "make_false", method_atomic_boolean_make_false, 0);
44+
45+
// CAtomicFixnum
46+
rb_define_alloc_func(rb_cAtomicFixnum, atomic_fixnum_allocate);
47+
rb_define_method(rb_cAtomicFixnum, "initialize", method_atomic_fixnum_initialize, -1);
48+
rb_define_method(rb_cAtomicFixnum, "value", method_atomic_fixnum_value, 0);
49+
rb_define_method(rb_cAtomicFixnum, "value=", method_atomic_fixnum_value_set, 1);
50+
rb_define_method(rb_cAtomicFixnum, "increment", method_atomic_fixnum_increment, 0);
51+
rb_define_method(rb_cAtomicFixnum, "decrement", method_atomic_fixnum_decrement, 0);
52+
rb_define_method(rb_cAtomicFixnum, "compare_and_set", method_atomic_fixnum_compare_and_set, 2);
53+
rb_define_alias(rb_cAtomicFixnum, "up", "increment");
54+
rb_define_alias(rb_cAtomicFixnum, "down", "decrement");
2855
}

0 commit comments

Comments
 (0)