mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* thread.c (rb_barrier_{new,wait,release,destroy}): use Mutex so that
circular requires fail with deadlock. [ruby-core:19821] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20229 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
2228f91851
commit
31f16d7729
3 changed files with 22 additions and 137 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
Thu Nov 13 06:08:44 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* thread.c (rb_barrier_{new,wait,release,destroy}): use Mutex so that
|
||||||
|
circular requires fail with deadlock. [ruby-core:19821]
|
||||||
|
|
||||||
Wed Nov 12 07:16:01 2008 David Flanagan <david@think32>
|
Wed Nov 12 07:16:01 2008 David Flanagan <david@think32>
|
||||||
|
|
||||||
* ruby.c (set_internal_encoding_once): fix typo in error string
|
* ruby.c (set_internal_encoding_once): fix typo in error string
|
||||||
|
|
148
thread.c
148
thread.c
|
@ -3032,164 +3032,44 @@ rb_mutex_synchronize(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg)
|
||||||
/*
|
/*
|
||||||
* Document-class: Barrier
|
* Document-class: Barrier
|
||||||
*/
|
*/
|
||||||
typedef struct rb_thread_list_struct rb_thread_list_t;
|
|
||||||
|
|
||||||
struct rb_thread_list_struct {
|
|
||||||
rb_thread_t *th;
|
|
||||||
rb_thread_list_t *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
thlist_mark(void *ptr)
|
|
||||||
{
|
|
||||||
rb_thread_list_t *q = ptr;
|
|
||||||
|
|
||||||
for (; q; q = q->next) {
|
|
||||||
rb_gc_mark(q->th->self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
thlist_free(void *ptr)
|
|
||||||
{
|
|
||||||
rb_thread_list_t *q = ptr, *next;
|
|
||||||
|
|
||||||
for (; q; q = next) {
|
|
||||||
next = q->next;
|
|
||||||
ruby_xfree(q);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
thlist_signal(rb_thread_list_t **list, unsigned int maxth, rb_thread_t **woken_thread)
|
|
||||||
{
|
|
||||||
int woken = 0;
|
|
||||||
rb_thread_list_t *q;
|
|
||||||
|
|
||||||
while ((q = *list) != NULL) {
|
|
||||||
rb_thread_t *th = q->th;
|
|
||||||
|
|
||||||
*list = q->next;
|
|
||||||
ruby_xfree(q);
|
|
||||||
if (th->status != THREAD_KILLED) {
|
|
||||||
rb_thread_ready(th);
|
|
||||||
if (!woken && woken_thread) *woken_thread = th;
|
|
||||||
if (++woken >= maxth && maxth) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!woken && woken_thread) *woken_thread = 0;
|
|
||||||
return woken;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
rb_thread_t *owner;
|
|
||||||
rb_thread_list_t *waiting, **tail;
|
|
||||||
} rb_barrier_t;
|
|
||||||
|
|
||||||
static void
|
|
||||||
barrier_mark(void *ptr)
|
|
||||||
{
|
|
||||||
rb_barrier_t *b = ptr;
|
|
||||||
|
|
||||||
if (b->owner) rb_gc_mark(b->owner->self);
|
|
||||||
thlist_mark(b->waiting);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
barrier_free(void *ptr)
|
|
||||||
{
|
|
||||||
rb_barrier_t *b = ptr;
|
|
||||||
|
|
||||||
b->owner = 0;
|
|
||||||
thlist_free(b->waiting);
|
|
||||||
b->waiting = 0;
|
|
||||||
ruby_xfree(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
barrier_alloc(VALUE klass)
|
barrier_alloc(VALUE klass)
|
||||||
{
|
{
|
||||||
VALUE volatile obj;
|
return Data_Wrap_Struct(klass, rb_gc_mark, 0, (void *)mutex_alloc(0));
|
||||||
rb_barrier_t *barrier;
|
|
||||||
|
|
||||||
obj = Data_Make_Struct(klass, rb_barrier_t, barrier_mark, barrier_free, barrier);
|
|
||||||
barrier->owner = GET_THREAD();
|
|
||||||
barrier->waiting = 0;
|
|
||||||
barrier->tail = &barrier->waiting;
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_barrier_new(void)
|
rb_barrier_new(void)
|
||||||
{
|
{
|
||||||
return barrier_alloc(rb_cBarrier);
|
VALUE barrier = barrier_alloc(rb_cBarrier);
|
||||||
}
|
rb_mutex_lock((VALUE)DATA_PTR(barrier));
|
||||||
|
return barrier;
|
||||||
static int
|
|
||||||
rb_barrier_signal(rb_barrier_t *barrier, unsigned int maxth)
|
|
||||||
{
|
|
||||||
int n = thlist_signal(&barrier->waiting, maxth, &barrier->owner);
|
|
||||||
if (!barrier->waiting) barrier->tail = &barrier->waiting;
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_barrier_wait(VALUE self)
|
rb_barrier_wait(VALUE self)
|
||||||
{
|
{
|
||||||
rb_barrier_t *barrier;
|
VALUE mutex = (VALUE)DATA_PTR(self);
|
||||||
rb_thread_list_t *q;
|
|
||||||
rb_thread_t *th = GET_THREAD();
|
|
||||||
|
|
||||||
Data_Get_Struct(self, rb_barrier_t, barrier);
|
if (!mutex) return Qfalse;
|
||||||
if (!barrier->tail) return Qfalse;
|
rb_mutex_lock(mutex);
|
||||||
if (!barrier->owner || barrier->owner->status == THREAD_KILLED) {
|
if (DATA_PTR(self)) return Qtrue;
|
||||||
barrier->owner = 0;
|
rb_mutex_unlock(mutex);
|
||||||
if (rb_barrier_signal(barrier, 1)) return Qfalse;
|
return Qfalse;
|
||||||
barrier->owner = th;
|
|
||||||
return Qtrue;
|
|
||||||
}
|
|
||||||
else if (barrier->owner == th) {
|
|
||||||
return Qfalse;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*barrier->tail = q = ALLOC(rb_thread_list_t);
|
|
||||||
q->th = th;
|
|
||||||
q->next = 0;
|
|
||||||
barrier->tail = &q->next;
|
|
||||||
rb_thread_sleep_forever();
|
|
||||||
if (!barrier->tail) return Qfalse;
|
|
||||||
return barrier->owner == th ? Qtrue : Qfalse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static rb_barrier_t *
|
|
||||||
rb_barrier_owned_ptr(VALUE self)
|
|
||||||
{
|
|
||||||
rb_barrier_t *barrier;
|
|
||||||
|
|
||||||
Data_Get_Struct(self, rb_barrier_t, barrier);
|
|
||||||
if (barrier->owner != GET_THREAD()) {
|
|
||||||
rb_raise(rb_eThreadError, "not owned");
|
|
||||||
}
|
|
||||||
return barrier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_barrier_release(VALUE self)
|
rb_barrier_release(VALUE self)
|
||||||
{
|
{
|
||||||
rb_barrier_t *barrier = rb_barrier_owned_ptr(self);
|
return rb_mutex_unlock((VALUE)DATA_PTR(self));
|
||||||
unsigned int n = rb_barrier_signal(barrier, 0);
|
|
||||||
return n ? UINT2NUM(n) : Qfalse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_barrier_destroy(VALUE self)
|
rb_barrier_destroy(VALUE self)
|
||||||
{
|
{
|
||||||
rb_barrier_t *barrier = rb_barrier_owned_ptr(self);
|
VALUE mutex = (VALUE)DATA_PTR(self);
|
||||||
int n = thlist_signal(&barrier->waiting, 0, 0);
|
DATA_PTR(self) = 0;
|
||||||
barrier->owner = 0;
|
return rb_mutex_unlock(mutex);
|
||||||
barrier->tail = 0;
|
|
||||||
return n ? UINT2NUM(n) : Qfalse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* variables for recursive traversals */
|
/* variables for recursive traversals */
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#define RUBY_VERSION "1.9.0"
|
#define RUBY_VERSION "1.9.0"
|
||||||
#define RUBY_RELEASE_DATE "2008-11-12"
|
#define RUBY_RELEASE_DATE "2008-11-13"
|
||||||
#define RUBY_VERSION_CODE 190
|
#define RUBY_VERSION_CODE 190
|
||||||
#define RUBY_RELEASE_CODE 20081112
|
#define RUBY_RELEASE_CODE 20081113
|
||||||
#define RUBY_PATCHLEVEL 0
|
#define RUBY_PATCHLEVEL 0
|
||||||
|
|
||||||
#define RUBY_VERSION_MAJOR 1
|
#define RUBY_VERSION_MAJOR 1
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
#define RUBY_VERSION_TEENY 0
|
#define RUBY_VERSION_TEENY 0
|
||||||
#define RUBY_RELEASE_YEAR 2008
|
#define RUBY_RELEASE_YEAR 2008
|
||||||
#define RUBY_RELEASE_MONTH 11
|
#define RUBY_RELEASE_MONTH 11
|
||||||
#define RUBY_RELEASE_DAY 12
|
#define RUBY_RELEASE_DAY 13
|
||||||
|
|
||||||
#ifdef RUBY_EXTERN
|
#ifdef RUBY_EXTERN
|
||||||
RUBY_EXTERN const char ruby_version[];
|
RUBY_EXTERN const char ruby_version[];
|
||||||
|
|
Loading…
Reference in a new issue