8000 Fix for 14634 by tenderlove · Pull Request #40 · github/ruby · GitHub
[go: up one dir, main page]

Skip to content

Fix for 14634 #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 24, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
8000 Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
thread_sync: redo r62934 to use fork_gen
Instead of maintaining linked-lists to store all
rb_queue/rb_szqueue/rb_condvar structs; store only a fork_gen
serial number to simplify management of these items.

This reduces initialization costs and avoids the up-front cost
of resetting all Queue/SizedQueue/ConditionVariable objects at
fork while saving 8 bytes per-structure on 64-bit.  There are no
savings on 32-bit.

* thread.c (rb_thread_atfork_internal): remove rb_thread_sync_reset_all call
* thread_sync.c (rb_thread_sync_reset_all): remove
* thread_sync.c (queue_live): remove
* thread_sync.c (queue_free): remove
* thread_sync.c (struct rb_queue): s/live/fork_gen/
* thread_sync.c (queue_data_type): use default free
* thread_sync.c (queue_alloc): remove list_add
* thread_sync.c (queue_fork_check): new function
* thread_sync.c (queue_ptr): call queue_fork_check
* thread_sync.c (szqueue_free): remove
* thread_sync.c (szqueue_data_type): use default free
* thread_sync.c (szqueue_alloc): remove list_add
* thread_sync.c (szqueue_ptr):  check fork_gen via queue_fork_check
* thread_sync.c (struct rb_condvar): s/live/fork_gen/
* thread_sync.c (condvar_free): remove
* thread_sync.c (cv_data_type): use default free
* thread_sync.c (condvar_ptr): check fork_gen
* thread_sync.c (condvar_alloc): remove list_add
  [ruby-core:86316] [Bug #14634]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63215 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
normal authored and tenderlove committed Jul 24, 2018
commit ca9b30a36578cdb0596e6f4629968e2872f7f6ea
1 change: 0 additions & 1 deletion thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -4189,7 +4189,6 @@ rb_thread_atfork_internal(rb_thread_t *th, void (*atfork)(rb_thread_t *, const r
rb_vm_living_threads_init(vm);
rb_vm_living_threads_insert(vm, th);
vm->fork_gen++;
rb_thread_sync_reset_all();

vm->sleeper = 0;
clear_coverage();
Expand Down
94 changes: 33 additions & 61 deletions thread_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ typedef struct rb_mutex_struct {
static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
static void rb_mutex_abandon_keeping_mutexes(rb_thread_t *th);
static void rb_mutex_abandon_locking_mutex(rb_thread_t *th);
static void rb_thread_sync_reset_all(void);
#endif
static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th);

Expand Down Expand Up @@ -544,17 +543,15 @@ void rb_mutex_allow_trap(VALUE self, int val)
/* Queue */

#define queue_waitq(q) UNALIGNED_MEMBER_PTR(q, waitq)
#define queue_live(q) UNALIGNED_MEMBER_PTR(q, live)
PACKED_STRUCT_UNALIGNED(struct rb_queue {
struct list_node live;
struct list_head waitq;
rb_serial_t fork_gen;
const VALUE que;
int num_waiting;
});

#define szqueue_waitq(sq) UNALIGNED_MEMBER_PTR(sq, q.waitq)
#define szqueue_pushq(sq) UNALIGNED_MEMBER_PTR(sq, pushq)
#define szqueue_live(sq) UNALIGNED_MEMBER_PTR(sq, q.live)
PACKED_STRUCT_UNALIGNED(struct rb_szqueue {
struct rb_queue q;
int num_waiting_push;
Expand All @@ -571,14 +568,6 @@ queue_mark(void *ptr)
rb_gc_mark(q->que);
}

static void
queue_free(void *ptr)
{
struct rb_queue *q = ptr;
list_del(queue_live(q));
ruby_xfree(ptr);
}

static size_t
queue_memsize(const void *ptr)
{
Expand All @@ -587,7 +576,7 @@ queue_memsize(const void *ptr)

static const rb_data_type_t queue_data_type = {
"queue",
{queue_mark, queue_free, queue_memsize,},
{queue_mark, RUBY_TYPED_DEFAULT_FREE, queue_memsize,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};

Expand All @@ -599,16 +588,32 @@ queue_alloc(VALUE klass)

obj = TypedData_Make_Struct(klass, struct rb_queue, &queue_data_type, q);
list_head_init(queue_waitq(q));
list_add(&queue_list, queue_live(q));
return obj;
}

static int
queue_fork_check(struct rb_queue *q)
{
rb_serial_t fork_gen = GET_VM()->fork_gen;

if (q->fork_gen == fork_gen) {
return 0;
}
/* forked children can't reach into parent thread stacks */
q->fork_gen = fork_gen;
list_head_init(queue_waitq(q));
q->num_waiting = 0;
return 1;
}

static struct rb_queue *
queue_ptr(VALUE obj)
{
struct rb_queue *q;

TypedData_Get_Struct(obj, struct rb_queue, &queue_data_type, q);
queue_fork_check(q);

return q;
}

Expand All @@ -622,14 +627,6 @@ szqueue_mark(void *ptr)
queue_mark(&sq->q);
}

static void
szqueue_free(void *ptr)
{
struct rb_szqueue *sq = ptr;
list_del(szqueue_live(sq));
ruby_xfree(ptr);
}

static size_t
szqueue_memsize(const void *ptr)
{
Expand All @@ -638,7 +635,7 @@ szqueue_memsize(const void *ptr)

static const rb_data_type_t szqueue_data_type = {
"sized_queue",
{szqueue_mark, szqueue_free, szqueue_memsize,},
{szqueue_mark, RUBY_TYPED_DEFAULT_FREE, szqueue_memsize,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};

Expand All @@ -650,7 +647,6 @@ szqueue_alloc(VALUE klass)
&szqueue_data_type, sq);
list_head_init(szqueue_waitq(sq));
list_head_init(szqueue_pushq(sq));
list_add(&szqueue_list, szqueue_live(sq));
return obj;
}

Expand All @@ -660,6 +656,11 @@ szqueue_ptr(VALUE obj)
struct rb_szqueue *sq;

TypedData_Get_Struct(obj, struct rb_szqueue, &szqueue_data_type, sq);
if (queue_fork_check(&sq->q)) {
list_head_init(szqueue_pushq(sq));
sq->num_waiting_push = 0;
}

return sq;
}

Expand Down Expand Up @@ -1239,10 +1240,9 @@ rb_szqueue_empty_p(VALUE self)


/* ConditionalVariable */
/* TODO: maybe this can be IMEMO */
struct rb_condvar {
struct list_head waitq;
struct list_node live;
rb_serial_t fork_gen;
};

/*
Expand Down Expand Up @@ -1273,14 +1273,6 @@ struct rb_condvar {
* }
*/

static void
condvar_free(void *ptr)
{
struct rb_condvar *cv = ptr;
list_del(&cv->live);
ruby_xfree(ptr);
}

static size_t
condvar_memsize(const void *ptr)
{
Expand All @@ -1289,17 +1281,23 @@ condvar_memsize(const void *ptr)

static const rb_data_type_t cv_data_type = {
"condvar",
{0, condvar_free, condvar_memsize,},
{0, RUBY_TYPED_DEFAULT_FREE, condvar_memsize,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};

static struct rb_condvar *
condvar_ptr(VALUE self)
{
struct rb_condvar *cv;
rb_serial_t fork_gen = GET_VM()->fork_gen;

TypedData_Get_Struct(self, struct rb_condvar, &cv_data_type, cv);

/* forked children can't reach into parent thread stacks */
if (cv->fork_gen != fork_gen) {
list_head_init(&cv->waitq);
}

return cv;
}

Expand All @@ -1311,7 +1309,6 @@ condvar_alloc(VALUE klass)

obj = TypedData_Make_Struct(klass, struct rb_condvar, &cv_data_type, cv);
list_head_init(&cv->waitq);
list_add(&condvar_list, &cv->live);

return obj;
}
Expand Down Expand Up @@ -1425,31 +1422,6 @@ define_thread_class(VALUE outer, const char *name, VALUE super)
return klass;
}

#if defined(HAVE_WORKING_FORK)
/* we must not reference stacks of dead threads in a forked child */
static void
rb_thread_sync_reset_all(void)
{
struct rb_queue *q = 0;
struct rb_szqueue *sq = 0;
struct rb_condvar *cv = 0;

list_for_each(&queue_list, q, live) {
list_head_init(queue_waitq(q));
q->num_waiting = 0;
}
list_for_each(&szqueue_list, sq, q.live) {
list_head_init(szqueue_waitq(sq));
list_head_init(szqueue_pushq(sq));
sq->num_waiting_push = 0;
sq->q.num_waiting = 0;
}
list_for_each(&condvar_list, cv, live) {
list_head_init(&cv->waitq);
}
}
#endif

static void
Init_thread_sync(void)
{
Expand Down
0