* thread.c (thread_join_sleep): check spurious wakeup by itself for
corresponding status change in trap context. * vm_core.h (struct rb_thread_struct): add rb_thread_list_t and use as join_list for reentry by trap context. * thread.c (thread_start_func_2): ditto. * thread.c (remove_from_join_list): ditto. * thread.c (rb_thread_atfork): ditto. * thread.c (thread_join): ditto. & remove trap handler check. * thread.c (sleep_forever): add argument : spurious_check. * thread.c (sleep_timeval): ditto. * thread.c (rb_thread_sleep_forever): set spurious_check. * thread.c (rb_thread_sleep_deadly): ditto. * thread.c (sleep_for_polling): ditto. * thread.c (rb_thread_wait_for): ditto. * thread.c (sleep_wait_for_interrupt): bypass spurious_check. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37937 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
ac93d931fa
commit
f5dc27aa77
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
|||||||
|
Wed Nov 28 21:31:21 2012 Masaya Tarui <tarui@ruby-lang.org>
|
||||||
|
|
||||||
|
* thread.c (thread_join_sleep): check spurious wakeup by itself for
|
||||||
|
corresponding status change in trap context.
|
||||||
|
* vm_core.h (struct rb_thread_struct): add rb_thread_list_t and use as join_list for
|
||||||
|
reentry by trap context.
|
||||||
|
* thread.c (thread_start_func_2): ditto.
|
||||||
|
* thread.c (remove_from_join_list): ditto.
|
||||||
|
* thread.c (rb_thread_atfork): ditto.
|
||||||
|
* thread.c (thread_join): ditto. & remove trap handler check.
|
||||||
|
* thread.c (sleep_forever): add argument : spurious_check.
|
||||||
|
* thread.c (sleep_timeval): ditto.
|
||||||
|
* thread.c (rb_thread_sleep_forever): set spurious_check.
|
||||||
|
* thread.c (rb_thread_sleep_deadly): ditto.
|
||||||
|
* thread.c (sleep_for_polling): ditto.
|
||||||
|
* thread.c (rb_thread_wait_for): ditto.
|
||||||
|
* thread.c (sleep_wait_for_interrupt): bypass spurious_check.
|
||||||
|
|
||||||
Wed Nov 28 21:23:18 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Wed Nov 28 21:23:18 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* ext/psych/yaml/emitter.c (yaml_emitter_write_indicator): constify.
|
* ext/psych/yaml/emitter.c (yaml_emitter_write_indicator): constify.
|
||||||
|
68
thread.c
68
thread.c
@ -63,9 +63,9 @@
|
|||||||
VALUE rb_cMutex;
|
VALUE rb_cMutex;
|
||||||
VALUE rb_cThreadShield;
|
VALUE rb_cThreadShield;
|
||||||
|
|
||||||
static void sleep_timeval(rb_thread_t *th, struct timeval time);
|
static void sleep_timeval(rb_thread_t *th, struct timeval time, int spurious_check);
|
||||||
static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec);
|
static void sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec, int spurious_check);
|
||||||
static void sleep_forever(rb_thread_t *th, int nodeadlock);
|
static void sleep_forever(rb_thread_t *th, int nodeadlock, int spurious_check);
|
||||||
static double timeofday(void);
|
static double timeofday(void);
|
||||||
static int rb_threadptr_dead(rb_thread_t *th);
|
static int rb_threadptr_dead(rb_thread_t *th);
|
||||||
static void rb_check_deadlock(rb_vm_t *vm);
|
static void rb_check_deadlock(rb_vm_t *vm);
|
||||||
@ -443,7 +443,7 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s
|
|||||||
int state;
|
int state;
|
||||||
VALUE args = th->first_args;
|
VALUE args = th->first_args;
|
||||||
rb_proc_t *proc;
|
rb_proc_t *proc;
|
||||||
rb_thread_t *join_th;
|
rb_thread_list_t *join_list;
|
||||||
rb_thread_t *main_th;
|
rb_thread_t *main_th;
|
||||||
VALUE errinfo = Qnil;
|
VALUE errinfo = Qnil;
|
||||||
# ifdef USE_SIGALTSTACK
|
# ifdef USE_SIGALTSTACK
|
||||||
@ -532,16 +532,16 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* wake up joining threads */
|
/* wake up joining threads */
|
||||||
join_th = th->join_list_head;
|
join_list = th->join_list;
|
||||||
while (join_th) {
|
while (join_list) {
|
||||||
if (join_th == main_th) errinfo = Qnil;
|
if (join_list->th == main_th) errinfo = Qnil;
|
||||||
rb_threadptr_interrupt(join_th);
|
rb_threadptr_interrupt(join_list->th);
|
||||||
switch (join_th->status) {
|
switch (join_list->th->status) {
|
||||||
case THREAD_STOPPED: case THREAD_STOPPED_FOREVER:
|
case THREAD_STOPPED: case THREAD_STOPPED_FOREVER:
|
||||||
join_th->status = THREAD_RUNNABLE;
|
join_list->th->status = THREAD_RUNNABLE;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
join_th = join_th->join_list_next;
|
join_list = join_list->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_threadptr_unlock_all_locking_mutexes(th);
|
rb_threadptr_unlock_all_locking_mutexes(th);
|
||||||
@ -686,14 +686,14 @@ remove_from_join_list(VALUE arg)
|
|||||||
rb_thread_t *target_th = p->target, *th = p->waiting;
|
rb_thread_t *target_th = p->target, *th = p->waiting;
|
||||||
|
|
||||||
if (target_th->status != THREAD_KILLED) {
|
if (target_th->status != THREAD_KILLED) {
|
||||||
rb_thread_t **pth = &target_th->join_list_head;
|
rb_thread_list_t **p = &target_th->join_list;
|
||||||
|
|
||||||
while (*pth) {
|
while (*p) {
|
||||||
if (*pth == th) {
|
if ((*p)->th == th) {
|
||||||
*pth = th->join_list_next;
|
*p = (*p)->next;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pth = &(*pth)->join_list_next;
|
p = &(*p)->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,7 +709,7 @@ thread_join_sleep(VALUE arg)
|
|||||||
|
|
||||||
while (target_th->status != THREAD_KILLED) {
|
while (target_th->status != THREAD_KILLED) {
|
||||||
if (p->forever) {
|
if (p->forever) {
|
||||||
sleep_forever(th, 1);
|
sleep_forever(th, 1, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
now = timeofday();
|
now = timeofday();
|
||||||
@ -718,7 +718,7 @@ thread_join_sleep(VALUE arg)
|
|||||||
(void *)target_th->thread_id);
|
(void *)target_th->thread_id);
|
||||||
return Qfalse;
|
return Qfalse;
|
||||||
}
|
}
|
||||||
sleep_wait_for_interrupt(th, limit - now);
|
sleep_wait_for_interrupt(th, limit - now, 0);
|
||||||
}
|
}
|
||||||
thread_debug("thread_join: interrupted (thid: %p)\n",
|
thread_debug("thread_join: interrupted (thid: %p)\n",
|
||||||
(void *)target_th->thread_id);
|
(void *)target_th->thread_id);
|
||||||
@ -738,10 +738,6 @@ thread_join(rb_thread_t *target_th, double delay)
|
|||||||
if (GET_VM()->main_thread == target_th) {
|
if (GET_VM()->main_thread == target_th) {
|
||||||
rb_raise(rb_eThreadError, "Target thread must not be main thread");
|
rb_raise(rb_eThreadError, "Target thread must not be main thread");
|
||||||
}
|
}
|
||||||
/* When running trap handler */
|
|
||||||
if (th->interrupt_mask & TRAP_INTERRUPT_MASK) {
|
|
||||||
rb_raise(rb_eThreadError, "can't be called from trap context");
|
|
||||||
}
|
|
||||||
|
|
||||||
arg.target = target_th;
|
arg.target = target_th;
|
||||||
arg.waiting = th;
|
arg.waiting = th;
|
||||||
@ -751,8 +747,10 @@ thread_join(rb_thread_t *target_th, double delay)
|
|||||||
thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
|
thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
|
||||||
|
|
||||||
if (target_th->status != THREAD_KILLED) {
|
if (target_th->status != THREAD_KILLED) {
|
||||||
th->join_list_next = target_th->join_list_head;
|
rb_thread_list_t list;
|
||||||
target_th->join_list_head = th;
|
list.next = target_th->join_list;
|
||||||
|
list.th = th;
|
||||||
|
target_th->join_list = &list;
|
||||||
if (!rb_ensure(thread_join_sleep, (VALUE)&arg,
|
if (!rb_ensure(thread_join_sleep, (VALUE)&arg,
|
||||||
remove_from_join_list, (VALUE)&arg)) {
|
remove_from_join_list, (VALUE)&arg)) {
|
||||||
return Qnil;
|
return Qnil;
|
||||||
@ -876,7 +874,7 @@ double2timeval(double d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sleep_forever(rb_thread_t *th, int deadlockable)
|
sleep_forever(rb_thread_t *th, int deadlockable,int spurious_check)
|
||||||
{
|
{
|
||||||
enum rb_thread_status prev_status = th->status;
|
enum rb_thread_status prev_status = th->status;
|
||||||
enum rb_thread_status status = deadlockable ? THREAD_STOPPED_FOREVER : THREAD_STOPPED;
|
enum rb_thread_status status = deadlockable ? THREAD_STOPPED_FOREVER : THREAD_STOPPED;
|
||||||
@ -892,7 +890,7 @@ sleep_forever(rb_thread_t *th, int deadlockable)
|
|||||||
th->vm->sleeper--;
|
th->vm->sleeper--;
|
||||||
}
|
}
|
||||||
RUBY_VM_CHECK_INTS_BLOCKING(th);
|
RUBY_VM_CHECK_INTS_BLOCKING(th);
|
||||||
} while (th->status == status);
|
} while (spurious_check && th->status == status);
|
||||||
th->status = prev_status;
|
th->status = prev_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -913,7 +911,7 @@ getclockofday(struct timeval *tp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sleep_timeval(rb_thread_t *th, struct timeval tv)
|
sleep_timeval(rb_thread_t *th, struct timeval tv,int spurious_check)
|
||||||
{
|
{
|
||||||
struct timeval to, tvn;
|
struct timeval to, tvn;
|
||||||
enum rb_thread_status prev_status = th->status;
|
enum rb_thread_status prev_status = th->status;
|
||||||
@ -940,7 +938,7 @@ sleep_timeval(rb_thread_t *th, struct timeval tv)
|
|||||||
--tv.tv_sec;
|
--tv.tv_sec;
|
||||||
tv.tv_usec += 1000000;
|
tv.tv_usec += 1000000;
|
||||||
}
|
}
|
||||||
} while (th->status == THREAD_STOPPED);
|
} while (spurious_check && th->status == THREAD_STOPPED);
|
||||||
th->status = prev_status;
|
th->status = prev_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,14 +946,14 @@ void
|
|||||||
rb_thread_sleep_forever(void)
|
rb_thread_sleep_forever(void)
|
||||||
{
|
{
|
||||||
thread_debug("rb_thread_sleep_forever\n");
|
thread_debug("rb_thread_sleep_forever\n");
|
||||||
sleep_forever(GET_THREAD(), 0);
|
sleep_forever(GET_THREAD(), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rb_thread_sleep_deadly(void)
|
rb_thread_sleep_deadly(void)
|
||||||
{
|
{
|
||||||
thread_debug("rb_thread_sleep_deadly\n");
|
thread_debug("rb_thread_sleep_deadly\n");
|
||||||
sleep_forever(GET_THREAD(), 1);
|
sleep_forever(GET_THREAD(), 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double
|
static double
|
||||||
@ -976,9 +974,9 @@ timeofday(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec)
|
sleep_wait_for_interrupt(rb_thread_t *th, double sleepsec,int spurious_check)
|
||||||
{
|
{
|
||||||
sleep_timeval(th, double2timeval(sleepsec));
|
sleep_timeval(th, double2timeval(sleepsec),spurious_check);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -987,14 +985,14 @@ sleep_for_polling(rb_thread_t *th)
|
|||||||
struct timeval time;
|
struct timeval time;
|
||||||
time.tv_sec = 0;
|
time.tv_sec = 0;
|
||||||
time.tv_usec = 100 * 1000; /* 0.1 sec */
|
time.tv_usec = 100 * 1000; /* 0.1 sec */
|
||||||
sleep_timeval(th, time);
|
sleep_timeval(th, time, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_thread_wait_for(struct timeval time)
|
rb_thread_wait_for(struct timeval time)
|
||||||
{
|
{
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
sleep_timeval(th, time);
|
sleep_timeval(th, time, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -3704,7 +3702,7 @@ void
|
|||||||
rb_thread_atfork(void)
|
rb_thread_atfork(void)
|
||||||
{
|
{
|
||||||
rb_thread_atfork_internal(terminate_atfork_i);
|
rb_thread_atfork_internal(terminate_atfork_i);
|
||||||
GET_THREAD()->join_list_head = 0;
|
GET_THREAD()->join_list = NULL;
|
||||||
|
|
||||||
/* We don't want reproduce CVE-2003-0900. */
|
/* We don't want reproduce CVE-2003-0900. */
|
||||||
rb_reset_random_seed();
|
rb_reset_random_seed();
|
||||||
|
10
vm_core.h
10
vm_core.h
@ -457,6 +457,13 @@ struct rb_mutex_struct;
|
|||||||
#define ALT_STACK_SIZE (4*1024)
|
#define ALT_STACK_SIZE (4*1024)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct rb_thread_struct;
|
||||||
|
typedef struct rb_thread_list_struct{
|
||||||
|
struct rb_thread_list_struct *next;
|
||||||
|
struct rb_thread_struct *th;
|
||||||
|
} rb_thread_list_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct rb_thread_struct {
|
typedef struct rb_thread_struct {
|
||||||
VALUE self;
|
VALUE self;
|
||||||
rb_vm_t *vm;
|
rb_vm_t *vm;
|
||||||
@ -546,8 +553,7 @@ typedef struct rb_thread_struct {
|
|||||||
/* storage */
|
/* storage */
|
||||||
st_table *local_storage;
|
st_table *local_storage;
|
||||||
|
|
||||||
struct rb_thread_struct *join_list_next;
|
rb_thread_list_t *join_list;
|
||||||
struct rb_thread_struct *join_list_head;
|
|
||||||
|
|
||||||
VALUE first_proc;
|
VALUE first_proc;
|
||||||
VALUE first_args;
|
VALUE first_args;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user