Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ca9b30a

Browse files
normaltenderlove
normal
authored andcommitted
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
1 parent 945bf91 commit ca9b30a

File tree

2 files changed

+33
-62
lines changed

2 files changed

+33
-62
lines changed

thread.c

-1
Original file line numberDiff line numberDiff line change
@@ -4189,7 +4189,6 @@ rb_thread_atfork_internal(rb_thread_t *th, void (*atfork)(rb_thread_t *, const r
41894189
rb_vm_living_threads_init(vm);
41904190
rb_vm_living_threads_insert(vm, th);
41914191
vm->fork_gen++;
4192-
rb_thread_sync_reset_all();
41934192

41944193
vm->sleeper = 0;
41954194
clear_coverage();

thread_sync.c

+33-61
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ typedef struct rb_mutex_struct {
6262
static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
6363
static void rb_mutex_abandon_keeping_mutexes(rb_thread_t *th);
6464
static void rb_mutex_abandon_locking_mutex(rb_thread_t *th);
65-
static void rb_thread_sync_reset_all(void);
6665
#endif
6766
static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t volatile *th);
6867

@@ -544,17 +543,15 @@ void rb_mutex_allow_trap(VALUE self, int val)
544543
/* Queue */
545544

546545
#define queue_waitq(q) UNALIGNED_MEMBER_PTR(q, waitq)
547-
#define queue_live(q) UNALIGNED_MEMBER_PTR(q, live)
548546
PACKED_STRUCT_UNALIGNED(struct rb_queue {
549-
struct list_node live;
550547
struct list_head waitq;
548+
rb_serial_t fork_gen;
551549
const VALUE que;
552550
int num_waiting;
553551
});
554552

555553
#define szqueue_waitq(sq) UNALIGNED_MEMBER_PTR(sq, q.waitq)
556554
#define szqueue_pushq(sq) UNALIGNED_MEMBER_PTR(sq, pushq)
557-
#define szqueue_live(sq) UNALIGNED_MEMBER_PTR(sq, q.live)
558555
PACKED_STRUCT_UNALIGNED(struct rb_szqueue {
559556
struct rb_queue q;
560557
int num_waiting_push;
@@ -571,14 +568,6 @@ queue_mark(void *ptr)
571568
rb_gc_mark(q->que);
572569
}
573570

574-
static void
575-
queue_free(void *ptr)
576-
{
577-
struct rb_queue *q = ptr;
578-
list_del(queue_live(q));
579-
ruby_xfree(ptr);
580-
}
581-
582571
static size_t
583572
queue_memsize(const void *ptr)
584573
{
@@ -587,7 +576,7 @@ queue_memsize(const void *ptr)
587576

588577
static const rb_data_type_t queue_data_type = {
589578
"queue",
590-
{queue_mark, queue_free, queue_memsize,},
579+
{queue_mark, RUBY_TYPED_DEFAULT_FREE, queue_memsize,},
591580
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
592581
};
593582

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

600589
obj = TypedData_Make_Struct(klass, struct rb_queue, &queue_data_type, q);
601590
list_head_init(queue_waitq(q));
602-
list_add(&queue_list, queue_live(q));
603591
return obj;
604592
}
605593

594+
static int
595+
queue_fork_check(struct rb_queue *q)
596+
{
597+
rb_serial_t fork_gen = GET_VM()->fork_gen;
598+
599+
if (q->fork_gen == fork_gen) {
600+
return 0;
601+
}
602+
/* forked children can't reach into parent thread stacks */
603+
q->fork_gen = fork_gen;
604+
list_head_init(queue_waitq(q));
605+
q->num_waiting = 0;
606+
return 1;
607+
}
608+
606609
static struct rb_queue *
607610
queue_ptr(VALUE obj)
608611
{
609612
struct rb_queue *q;
610613

611614
TypedData_Get_Struct(obj, struct rb_queue, &queue_data_type, q);
615+
queue_fork_check(q);
616+
612617
return q;
613618
}
614619

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

625-
static void
626-
szqueue_free(void *ptr)
627-
{
628-
struct rb_szqueue *sq = ptr;
629-
list_del(szqueue_live(sq));
630-
ruby_xfree(ptr);
631-
}
632-
633630
static size_t
634631
szqueue_memsize(const void *ptr)
635632
{
@@ -638,7 +635,7 @@ szqueue_memsize(const void *ptr)
638635

639636
static const rb_data_type_t szqueue_data_type = {
640637
"sized_queue",
641-
{szqueue_mark, szqueue_free, szqueue_memsize,},
638+
{szqueue_mark, RUBY_TYPED_DEFAULT_FREE, szqueue_memsize,},
642639
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
643640
};
644641

@@ -650,7 +647,6 @@ szqueue_alloc(VALUE klass)
650647
&szqueue_data_type, sq);
651648
list_head_init(szqueue_waitq(sq));
652649
list_head_init(szqueue_pushq(sq));
653-
list_add(&szqueue_list, szqueue_live(sq));
654650
return obj;
655651
}
656652

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

662658
TypedData_Get_Struct(obj, struct rb_szqueue, &szqueue_data_type, sq);
659+
if (queue_fork_check(&sq->q)) {
660+
list_head_init(szqueue_pushq(sq));
661+
sq->num_waiting_push = 0;
662+
}
663+
663664
return sq;
664665
}
665666

@@ -1239,10 +1240,9 @@ rb_szqueue_empty_p(VALUE self)
12391240

12401241

12411242
/* ConditionalVariable */
1242-
/* TODO: maybe this can be IMEMO */
12431243
struct rb_condvar {
12441244
struct list_head waitq;
1245-
struct list_node live;
1245+
rb_serial_t fork_gen;
12461246
};
12471247

12481248
/*
@@ -1273,14 +1273,6 @@ struct rb_condvar {
12731273
* }
12741274
*/
12751275

1276-
static void
1277-
condvar_free(void *ptr)
1278-
{
1279-
struct rb_condvar *cv = ptr;
1280-
list_del(&cv->live);
1281-
ruby_xfree(ptr);
1282-
}
1283-
12841276
static size_t
12851277
condvar_memsize(const void *ptr)
12861278
{
@@ -1289,17 +1281,23 @@ condvar_memsize(const void *ptr)
12891281

12901282
static const rb_data_type_t cv_data_type = {
12911283
"condvar",
1292-
{0, condvar_free, condvar_memsize,},
1284+
{0, RUBY_TYPED_DEFAULT_FREE, condvar_memsize,},
12931285
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
12941286
};
12951287

12961288
static struct rb_condvar *
12971289
condvar_ptr(VALUE self)
12981290
{
12991291
struct rb_condvar *cv;
1292+
rb_serial_t fork_gen = GET_VM()->fork_gen;
13001293

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

1296+
/* forked children can't reach into parent thread stacks */
1297+
if (cv->fork_gen != fork_gen) {
1298+
list_head_init(&cv->waitq);
1299+
}
1300+
13031301
return cv;
13041302
}
13051303

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

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

13161313
return obj;
13171314
}
@@ -1425,31 +1422,6 @@ define_thread_class(VALUE outer, const char *name, VALUE super)
14251422
return klass;
14261423
}
14271424

1428-
#if defined(HAVE_WORKING_FORK)
1429-
/* we must not reference stacks of dead threads in a forked child */
1430-
static void
1431-
rb_thread_sync_reset_all(void)
1432-
{
1433-
struct rb_queue *q = 0;
1434-
struct rb_szqueue *sq = 0;
1435-
struct rb_condvar *cv = 0;
1436-
1437-
list_for_each(&queue_list, q, live) {
1438-
list_head_init(queue_waitq(q));
1439-
q->num_waiting = 0;
1440-
}
1441-
list_for_each(&szqueue_list, sq, q.live) {
1442-
list_head_init(szqueue_waitq(sq));
1443-
list_head_init(szqueue_pushq(sq));
1444-
sq->num_waiting_push = 0;
1445-
sq->q.num_waiting = 0;
1446-
}
1447-
list_for_each(&condvar_list, cv, live) {
1448-
list_head_init(&cv->waitq);
1449-
}
1450-
}
1451-
#endif
1452-
14531425
static void
14541426
Init_thread_sync(void)
14551427
{

0 commit comments

Comments
 (0)