* [NothinkToDo] ThreadSafeRuby
@ 2002-07-31 15:27 Michal Rokos
2002-07-31 16:23 ` ts
0 siblings, 1 reply; 2+ messages in thread
From: Michal Rokos @ 2002-07-31 15:27 UTC (permalink / raw
To: ruby-core
Hi,
today I get a little bored, so I started to play with POSIX
threads.
My idea is to bring "real" threads to Ruby and also make Ruby
thread safe. My thoughts go like this: make OS dependent threads
and choose them in ./configure stage: ./configure
--with-threads=
POSIX (aka pthreads)
SW (software - current implementation)
...
Windows
...
As a 1st step I started to play with locking. Following diff
shows where I'm playing. Do you think that this would be useful
or shall I do something else? :-)
Michal
diff -urN ruby/ruby.h ruby-my/ruby.h
--- ruby/ruby.h 2002-05-14 07:22:26.000000000 +0100
+++ ruby-my/ruby.h 2002-07-31 15:29:41.000000000 +0100
@@ -20,6 +20,7 @@
#include "config.h"
#include "defines.h"
+#include "thread.h"
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
@@ -271,9 +272,10 @@
VALUE rb_newobj _((void));
#define NEWOBJ(obj,type) type *obj = (type*)rb_newobj()
-#define OBJSETUP(obj,c,t) do {\
+#define OBJSETUP(obj, c, t) do {\
RBASIC(obj)->flags = (t);\
RBASIC(obj)->klass = (c);\
+ LOCK_INIT(RBASIC(obj)->lck);\
if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\
} while (0)
#define CLONESETUP(clone,obj) do {\
@@ -289,6 +291,7 @@
struct RBasic {
unsigned long flags;
VALUE klass;
+ lock_t lck;
};
struct RObject {
@@ -453,6 +456,11 @@
#define MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(n))
#define MEMCMP(p1,p2,type,n) memcmp((p1), (p2), sizeof(type)*(n))
+#define rb_lock_wr(obj) LOCK_WR(RBASIC((obj))->lck)
+#define rb_lock_rd(obj) LOCK_RD(RBASIC((obj))->lck)
+#define rb_unlock_rd(obj) UNLOCK_RD(RBASIC((obj))->lck)
+#define rb_unlock_wr(obj) UNLOCK_WR(RBASIC((obj))->lck)
+
void rb_glob _((char*,void(*)(const char*,VALUE),VALUE));
void rb_globi _((char*,void(*)(const char*,VALUE),VALUE));
diff -urN ruby/thread.h ruby-my/thread.h
--- ruby/thread.h 1970-01-01 01:00:00.000000000 +0100
+++ ruby-my/thread.h 2002-07-31 15:26:55.000000000 +0100
@@ -0,0 +1,21 @@
+#if !defined(THREAD_H)
+#define THREAD_H
+
+#define _GNU_SOURCE 1
+#include <pthread.h>
+
+#define lock_t pthread_rwlock_t
+#define LOCK_INIT(lock) pthread_rwlock_init(&(lock), NULL)
+// PTHREAD_RWLOCK_INITIALIZER)
+#define LOCK_RD(lock) pthread_rwlock_rdlock(&(lock))
+#define UNLOCK_RD(lock) pthread_rwlock_unlock(&(lock))
+#define LOCK_WR(lock) pthread_rwlock_wrlock(&(lock))
+#define UNLOCK_WR(lock) pthread_rwlock_unlock(&(lock))
+
+#define mutex_t pthread_mutex_t
+#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define MUTEX_LOCK(mutex) pthread_mutex_lock((mutex))
+#define MUTEX_UNLOCK(mutex) pthread_mutex_unlock((mutex))
+
+#endif
+
diff -urN ruby/gc.c ruby-my/gc.c
--- ruby/gc.c 2002-07-26 09:52:56.000000000 +0100
+++ ruby-my/gc.c 2002-07-31 13:03:58.000000000 +0100
@@ -155,7 +155,6 @@
extern int ruby_in_compile;
static int dont_gc;
-static int during_gc;
static int need_call_final = 0;
static st_table *finalizer_table = 0;
@@ -251,6 +250,7 @@
} as;
} RVALUE;
+static mutex_t mutex = MUTEX_INITIALIZER;
static RVALUE *freelist = 0;
static RVALUE *deferred_final_list = 0;
@@ -317,10 +317,15 @@
{
VALUE obj;
- if (!freelist) rb_gc();
+ MUTEX_LOCK(&mutex);
+ if (!freelist) {
+ MUTEX_UNLOCK(&mutex);
+ rb_gc();
+ }
obj = (VALUE)freelist;
freelist = freelist->as.free.next;
+ MUTEX_UNLOCK(&mutex);
MEMZERO((void*)obj, RVALUE, 1);
return obj;
}
@@ -919,8 +924,10 @@
if (freed < FREE_MIN) {
add_heap();
}
+/*
+ * TODO: check this
during_gc = 0;
-
+ */
/* clear finalization list */
if (final_list) {
RVALUE *tmp;
@@ -1130,19 +1137,18 @@
jmp_buf save_regs_gc_mark;
SET_STACK_END;
- if (dont_gc || during_gc) {
+ MUTEX_LOCK(&mutex);
+ if (dont_gc) {
if (!freelist || malloc_memories > GC_MALLOC_LIMIT) {
malloc_memories = 0;
add_heap();
}
+ MUTEX_UNLOCK(&mutex);
return;
}
malloc_memories = 0;
- if (during_gc) return;
- during_gc++;
-
init_mark_stack();
/* mark frame stack */
@@ -1197,6 +1203,7 @@
}
}
gc_sweep();
+ MUTEX_UNLOCK(&mutex);
}
VALUE
diff -urN ruby/array.c ruby-my/array.c
--- ruby/array.c 2002-07-18 14:06:48.000000000 +0100
+++ ruby-my/array.c 2002-07-31 15:48:16.000000000 +0100
@@ -48,11 +48,19 @@
rb_ary_modify_check(ary)
VALUE ary;
{
- if (OBJ_FROZEN(ary)) rb_error_frozen("array");
- if (FL_TEST(ary, ARY_TMPLOCK))
+ rb_lock_wr(ary);
+ if (OBJ_FROZEN(ary)) {
+ rb_unlock_wr(ary);
+ rb_error_frozen("array");
+ }
+ if (FL_TEST(ary, ARY_TMPLOCK)) {
+ rb_unlock_wr(ary);
rb_raise(rb_eTypeError, "can't modify array during sort");
- if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4)
+ }
+ if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4) {
+ rb_unlock_wr(ary);
rb_raise(rb_eSecurityError, "Insecure: can't modify array");
+ }
}
static void
@@ -81,8 +89,12 @@
rb_ary_frozen_p(ary)
VALUE ary;
{
- if (FL_TEST(ary, FL_FREEZE|ARY_TMPLOCK))
+ rb_lock_rd(ary);
+ if (FL_TEST(ary, FL_FREEZE|ARY_TMPLOCK)) {
+ rb_unlock_rd(ary);
return Qtrue;
+ }
+ rb_unlock_rd(ary);
return Qfalse;
}
@@ -221,6 +233,7 @@
if (rb_block_given_p()) {
rb_warning("given block not used");
}
+ rb_unlock_wr(ary);
return ary;
}
@@ -228,15 +241,18 @@
val = rb_check_convert_type(size, T_ARRAY, "Array", "to_ary");
if (!NIL_P(val)) {
rb_ary_replace(ary, val);
+ rb_unlock_wr(ary);
return ary;
}
}
len = NUM2LONG(size);
if (len < 0) {
+ rb_unlock_wr(ary);
rb_raise(rb_eArgError, "negative array size");
}
if (len > 0 && len * sizeof(VALUE) <= 0) {
+ rb_unlock_wr(ary);
rb_raise(rb_eArgError, "array size too big");
}
if (len > RARRAY(ary)->aux.capa) {
@@ -247,6 +263,7 @@
long i;
if (argc > 1) {
+ rb_unlock_wr(ary);
rb_raise(rb_eArgError, "wrong number of arguments");
}
for (i=0; i<len; i++) {
@@ -258,7 +275,7 @@
memfill(RARRAY(ary)->ptr, len, val);
RARRAY(ary)->len = len;
}
-
+ rb_unlock_wr(ary);
return ary;
}
@@ -292,6 +309,7 @@
if (idx < 0) {
idx += RARRAY(ary)->len;
if (idx < 0) {
+ rb_unlock_wr(ary);
rb_raise(rb_eIndexError, "index %ld out of array",
idx - RARRAY(ary)->len);
}
@@ -314,6 +332,7 @@
RARRAY(ary)->len = idx + 1;
}
RARRAY(ary)->ptr[idx] = val;
+ rb_unlock_wr(ary);
}
VALUE
@@ -344,15 +363,22 @@
rb_ary_pop(ary)
VALUE ary;
{
+ VALUE item;
+
rb_ary_modify_check(ary);
- if (RARRAY(ary)->len == 0) return Qnil;
+ if (RARRAY(ary)->len == 0) {
+ rb_unlock_wr(ary);
+ return Qnil;
+ }
if (!FL_TEST(ary, ELTS_SHARED) &&
RARRAY(ary)->len * 2 < RARRAY(ary)->aux.capa &&
RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
}
- return RARRAY(ary)->ptr[--RARRAY(ary)->len];
+ item = RARRAY(ary)->ptr[--RARRAY(ary)->len];
+ rb_unlock_wr(ary);
+ return item;
}
static void
@@ -378,12 +404,15 @@
VALUE top;
rb_ary_modify_check(ary);
- if (RARRAY(ary)->len == 0) return Qnil;
+ if (RARRAY(ary)->len == 0) {
+ rb_unlock_wr(ary);
+ return Qnil;
+ }
top = RARRAY(ary)->ptr[0];
ary_make_shared(ary);
RARRAY(ary)->ptr++; /* shift ptr */
RARRAY(ary)->len--;
-
+ rb_unlock_wr(ary);
return top;
}
@@ -407,6 +436,7 @@
RARRAY(ary)->len++;
RARRAY(ary)->ptr[0] = item;
+ rb_unlock_wr(ary);
return ary;
}
@@ -685,6 +715,7 @@
}
MEMMOVE(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
}
+ rb_unlock_wr(ary);
}
static VALUE
@@ -1034,7 +1065,10 @@
VALUE tmp;
rb_ary_modify(ary);
- if (RARRAY(ary)->len <= 1) return ary;
+ if (RARRAY(ary)->len <= 1) {
+ rb_unlock_wr(ary);
+ return ary;
+ }
p1 = RARRAY(ary)->ptr;
p2 = p1 + RARRAY(ary)->len - 1; /* points last item */
@@ -1044,7 +1078,7 @@
*p1++ = *p2;
*p2-- = tmp;
}
-
+ rb_unlock_wr(ary);
return ary;
}
@@ -1115,7 +1149,6 @@
sort_unlock(ary)
VALUE ary;
{
- FL_UNSET(ary, ARY_TMPLOCK);
return ary;
}
@@ -1124,10 +1157,12 @@
VALUE ary;
{
rb_ary_modify(ary);
- if (RARRAY(ary)->len <= 1) return ary;
-
- FL_SET(ary, ARY_TMPLOCK); /* prohibit modification during sort */
+ if (RARRAY(ary)->len <= 1) {
+ rb_unlock_wr(ary);
+ return ary;
+ }
rb_ensure(sort_internal, ary, sort_unlock, ary);
+ rb_unlock_wr(ary);
return ary;
}
@@ -1169,6 +1204,7 @@
for (i = 0; i < RARRAY(ary)->len; i++) {
RARRAY(ary)->ptr[i] = rb_yield(RARRAY(ary)->ptr[i]);
}
+ rb_unlock_wr(ary);
return ary;
}
@@ -1216,8 +1252,10 @@
}
if (RARRAY(ary)->len == i2) {
if (rb_block_given_p()) {
+ rb_unlock_wr(ary);
return rb_yield(item);
}
+ rb_unlock_wr(ary);
return Qnil;
}
@@ -1227,7 +1265,7 @@
RARRAY(ary)->aux.capa = i2 * 2;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
}
-
+ rb_unlock_wr(ary);
return item;
}
@@ -1240,10 +1278,16 @@
VALUE del;
rb_ary_modify(ary);
- if (pos >= len) return Qnil;
+ if (pos >= len) {
+ rb_unlock_wr(ary);
+ return Qnil;
+ }
if (pos < 0) {
pos += len;
- if (pos < 0) return Qnil;
+ if (pos < 0) {
+ rb_unlock_wr(ary);
+ return Qnil;
+ }
}
del = RARRAY(ary)->ptr[pos];
@@ -1252,6 +1296,7 @@
}
RARRAY(ary)->len = pos;
+ rb_unlock_wr(ary);
return del;
}
@@ -1281,13 +1326,14 @@
}
arg2 = rb_ary_subseq(ary, pos, len);
rb_ary_update(ary, pos, len, Qnil); /* Qnil/rb_ary_new2(0) */
+ rb_unlock_wr(ary);
return arg2;
}
if (!FIXNUM_P(arg1) && rb_range_beg_len(arg1, &pos, &len, RARRAY(ary)->len, 1)) {
goto delete_pos_len;
}
-
+ rb_unlock_wr(ary);
return rb_ary_delete_at(ary, NUM2LONG(arg1));
}
@@ -1305,9 +1351,12 @@
}
i2++;
}
- if (RARRAY(ary)->len == i2) return Qnil;
+ if (RARRAY(ary)->len == i2) {
+ rb_unlock_wr(ary);
+ return Qnil;
+ }
RARRAY(ary)->len = i2;
-
+ rb_unlock_wr(ary);
return ary;
}
@@ -1348,6 +1397,7 @@
RARRAY(ary)->aux.capa = ARY_DEFAULT_SIZE * 2;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
}
+ rb_unlock_wr(ary);
return ary;
}
@@ -1414,6 +1464,7 @@
*p++ = item;
}
}
+ rb_unlock_wr(ary);
return ary;
}
@@ -1706,7 +1757,7 @@
p++;
}
RARRAY(ary)->len = (q - RARRAY(ary)->ptr);
-
+ rb_unlock_wr(ary);
return ary;
}
@@ -1734,11 +1785,12 @@
else *p++ = *t++;
}
if (RARRAY(ary)->len == (p - RARRAY(ary)->ptr)) {
+ rb_unlock_wr(ary);
return Qnil;
}
RARRAY(ary)->len = RARRAY(ary)->aux.capa = (p - RARRAY(ary)->ptr);
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
-
+ rb_unlock_wr(ary);
return ary;
}
@@ -1817,6 +1869,7 @@
}
i++;
}
+ rb_unlock_wr(ary);
if (mod == 0) return Qnil;
return ary;
}
--
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Michal Rokos Czech Technical University, Prague
E-mail:m.rokos@sh.cvut.cz ICQ:36118339 Jabber:majkl@jabber.cz
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [NothinkToDo] ThreadSafeRuby
2002-07-31 15:27 [NothinkToDo] ThreadSafeRuby Michal Rokos
@ 2002-07-31 16:23 ` ts
0 siblings, 0 replies; 2+ messages in thread
From: ts @ 2002-07-31 16:23 UTC (permalink / raw
To: ruby-core; +Cc: ruby-core
>>>>> "M" == Michal Rokos <m.rokos@sh.cvut.cz> writes:
M> struct RBasic {
M> unsigned long flags;
M> VALUE klass;
M> + lock_t lck;
M> };
be carefull with this and see [ruby-talk:5956]
* currently each internal structure sizes are made strictly less
than 5 pointer size for space efficiency.
Guy Decoux
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2002-07-31 16:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-07-31 15:27 [NothinkToDo] ThreadSafeRuby Michal Rokos
2002-07-31 16:23 ` ts
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).