57
57
#endif
58
58
#endif
59
59
60
- static size_t
61
- get_next_stk_size (rust_task_thread *thread, rust_task *task,
62
- size_t min, size_t current, size_t requested) {
63
- LOG (task, mem, " calculating new stack size for 0x%" PRIxPTR, task);
64
- LOG (task, mem,
65
- " min: %" PRIdPTR " current: %" PRIdPTR " requested: %" PRIdPTR,
66
- min, current, requested);
67
-
68
- // Allocate at least enough to accomodate the next frame
69
- size_t sz = std::max (min, requested);
70
-
71
- // And double the stack size each allocation
72
- const size_t max = 1024 * 1024 ;
73
- size_t next = std::min (max, current * 2 );
74
-
75
- sz = std::max (sz, next);
76
-
77
- LOG (task, mem, " next stack size: %" PRIdPTR, sz);
78
- I (thread, requested <= sz);
79
- return sz;
80
- }
81
-
82
- // Task stack segments. Heap allocated and chained together.
83
-
84
- // The amount of stack in a segment available to Rust code
85
- static size_t
86
- user_stack_size (stk_seg *stk) {
87
- return (size_t )(stk->end
88
- - (uintptr_t )&stk->data [0 ]
89
- - RED_ZONE_SIZE);
90
- }
91
-
92
- static void
93
- free_stk (rust_task *task, stk_seg *stk) {
94
- LOGPTR (task->thread , " freeing stk segment" , (uintptr_t )stk);
95
- task->total_stack_sz -= user_stack_size (stk);
96
- task->free (stk);
97
- }
98
-
99
- static stk_seg*
100
- new_stk (rust_task_thread *thread, rust_task *task, size_t requested_sz)
101
- {
102
- LOG (task, mem, " creating new stack for task %" PRIxPTR, task);
103
- if (task->stk ) {
104
- check_stack_canary (task->stk );
105
- }
106
-
107
- // The minimum stack size, in bytes, of a Rust stack, excluding red zone
108
- size_t min_sz = thread->min_stack_size ;
109
-
110
- // Try to reuse an existing stack segment
111
- if (task->stk != NULL && task->stk ->prev != NULL ) {
112
- size_t prev_sz = user_stack_size (task->stk ->prev );
113
- if (min_sz <= prev_sz && requested_sz <= prev_sz) {
114
- LOG (task, mem, " reusing existing stack" );
115
- task->stk = task->stk ->prev ;
116
- A (thread, task->stk ->prev == NULL , " Bogus stack ptr" );
117
- config_valgrind_stack (task->stk );
118
- return task->stk ;
119
- } else {
120
- LOG (task, mem, " existing stack is not big enough" );
121
- free_stk (task, task->stk ->prev );
122
- task->stk ->prev = NULL ;
123
- }
124
- }
125
-
126
- // The size of the current stack segment, excluding red zone
127
- size_t current_sz = 0 ;
128
- if (task->stk != NULL ) {
129
- current_sz = user_stack_size (task->stk );
130
- }
131
- // The calculated size of the new stack, excluding red zone
132
- size_t rust_stk_sz = get_next_stk_size (thread, task, min_sz,
133
- current_sz, requested_sz);
134
-
135
- if (task->total_stack_sz + rust_stk_sz > thread->env ->max_stack_size ) {
136
- LOG_ERR (task, task, " task %" PRIxPTR " ran out of stack" , task);
137
- task->fail ();
138
- }
139
-
140
- size_t sz = sizeof (stk_seg) + rust_stk_sz + RED_ZONE_SIZE;
141
- stk_seg *stk = (stk_seg *)task->malloc (sz, " stack" );
142
- LOGPTR (task->thread , " new stk" , (uintptr_t )stk);
143
- memset (stk, 0 , sizeof (stk_seg));
144
- add_stack_canary (stk);
145
- stk->prev = NULL ;
146
- stk->next = task->stk ;
147
- stk->end = (uintptr_t ) &stk->data [rust_stk_sz + RED_ZONE_SIZE];
148
- LOGPTR (task->thread , " stk end" , stk->end );
149
-
150
- task->stk = stk;
151
- config_valgrind_stack (task->stk );
152
- task->total_stack_sz += user_stack_size (stk);
153
- return stk;
154
- }
155
-
156
- static void
157
- del_stk (rust_task *task, stk_seg *stk)
158
- {
159
- assert (stk == task->stk && " Freeing stack segments out of order!" );
160
- check_stack_canary (stk);
161
-
162
- task->stk = stk->next ;
163
-
164
- bool delete_stack = false ;
165
- if (task->stk != NULL ) {
166
- // Don't actually delete this stack. Save it to reuse later,
167
- // preventing the pathological case where we repeatedly reallocate
168
- // the stack for the next frame.
169
- task->stk ->prev = stk;
170
- } else {
171
- // This is the last stack, delete it.
172
- delete_stack = true ;
173
- }
174
-
175
- // Delete the previous previous stack
176
- if (stk->prev != NULL ) {
177
- free_stk (task, stk->prev );
178
- stk->prev = NULL ;
179
- }
180
-
181
- unconfig_valgrind_stack (stk);
182
- if (delete_stack) {
183
- free_stk (task, stk);
184
- A (task->thread , task->total_stack_sz == 0 , " Stack size should be 0" );
185
- }
186
- }
60
+ extern " C" CDECL void
61
+ record_sp (void *limit);
187
62
188
63
// Tasks
189
64
rust_task::rust_task (rust_task_thread *thread, rust_task_list *state,
@@ -218,7 +93,7 @@ rust_task::rust_task(rust_task_thread *thread, rust_task_list *state,
218
93
LOGPTR (thread, " new task" , (uintptr_t )this );
219
94
DLOG (thread, task, " sizeof(task) = %d (0x%x)" , sizeof *this , sizeof *this );
220
95
221
- stk = new_stk (thread, this , init_stack_sz);
96
+ new_stack ( init_stack_sz);
222
97
if (supervisor) {
223
98
supervisor->ref ();
224
99
}
@@ -246,7 +121,7 @@ rust_task::delete_this()
246
121
// and no landing pads stopped to clean up.
247
122
// FIXME: We should do this when the task exits, not in the destructor
248
123
while (stk != NULL ) {
249
- del_stk ( this , stk );
124
+ del_stack ( );
250
125
}
251
126
252
127
thread->release_task (this );
@@ -630,16 +505,134 @@ rust_task::notify(bool success) {
630
505
}
631
506
}
632
507
633
- extern " C" CDECL void
634
- record_sp (void *limit);
508
+ size_t
509
+ rust_task::get_next_stack_size (size_t min, size_t current, size_t requested) {
510
+ LOG (this , mem, " calculating new stack size for 0x%" PRIxPTR, this );
511
+ LOG (this , mem,
512
+ " min: %" PRIdPTR " current: %" PRIdPTR " requested: %" PRIdPTR,
513
+ min, current, requested);
514
+
515
+ // Allocate at least enough to accomodate the next frame
516
+ size_t sz = std::max (min, requested);
517
+
518
+ // And double the stack size each allocation
519
+ const size_t max = 1024 * 1024 ;
520
+ size_t next = std::min (max, current * 2 );
521
+
522
+ sz = std::max (sz, next);
523
+
524
+ LOG (this , mem, " next stack size: %" PRIdPTR, sz);
525
+ I (thread, requested <= sz);
526
+ return sz;
527
+ }
528
+
529
+ // The amount of stack in a segment available to Rust code
530
+ static size_t
531
+ user_stack_size (stk_seg *stk) {
532
+ return (size_t )(stk->end
533
+ - (uintptr_t )&stk->data [0 ]
534
+ - RED_ZONE_SIZE);
535
+ }
536
+
537
+ void
538
+ rust_task::free_stack (stk_seg *stk) {
539
+ LOGPTR (thread, " freeing stk segment" , (uintptr_t )stk);
540
+ total_stack_sz -= user_stack_size (stk);
541
+ free (stk);
542
+ }
543
+
544
+ void
545
+ rust_task::new_stack (size_t requested_sz) {
546
+ LOG (this , mem, " creating new stack for task %" PRIxPTR, this );
547
+ if (stk) {
548
+ ::check_stack_canary (stk);
549
+ }
550
+
551
+ // The minimum stack size, in bytes, of a Rust stack, excluding red zone
552
+ size_t min_sz = thread->min_stack_size ;
553
+
554
+ // Try to reuse an existing stack segment
555
+ if (stk != NULL && stk->prev != NULL ) {
556
+ size_t prev_sz = user_stack_size (stk->prev );
557
+ if (min_sz <= prev_sz && requested_sz <= prev_sz) {
558
+ LOG (this , mem, " reusing existing stack" );
559
+ stk = stk->prev ;
560
+ A (thread, stk->prev == NULL , " Bogus stack ptr" );
561
+ config_valgrind_stack (stk);
562
+ return ;
563
+ } else {
564
+ LOG (this , mem, " existing stack is not big enough" );
565
+ free_stack (stk->prev );
566
+ stk->prev = NULL ;
567
+ }
568
+ }
569
+
570
+ // The size of the current stack segment, excluding red zone
571
+ size_t current_sz = 0 ;
572
+ if (stk != NULL ) {
573
+ current_sz = user_stack_size (stk);
574
+ }
575
+ // The calculated size of the new stack, excluding red zone
576
+ size_t rust_stk_sz = get_next_stack_size (min_sz,
577
+ current_sz, requested_sz);
578
+
579
+ if (total_stack_sz + rust_stk_sz > thread->env ->max_stack_size ) {
580
+ LOG_ERR (this , task, " task %" PRIxPTR " ran out of stack" , this );
581
+ fail ();
582
+ }
583
+
584
+ size_t sz = sizeof (stk_seg) + rust_stk_sz + RED_ZONE_SIZE;
585
+ stk_seg *new_stk = (stk_seg *)malloc (sz, " stack" );
586
+ LOGPTR (thread, " new stk" , (uintptr_t )new_stk);
587
+ memset (new_stk, 0 , sizeof (stk_seg));
588
+ add_stack_canary (new_stk);
589
+ new_stk->prev = NULL ;
590
+ new_stk->next = stk;
591
+ new_stk->end = (uintptr_t ) &new_stk->data [rust_stk_sz + RED_ZONE_SIZE];
592
+ LOGPTR (thread, " stk end" , new_stk->end );
593
+
594
+ stk = new_stk;
595
+ config_valgrind_stack (stk);
596
+ total_stack_sz += user_stack_size (new_stk);
597
+ }
598
+
599
+ void
600
+ rust_task::del_stack () {
601
+ stk_seg *old_stk = stk;
602
+ ::check_stack_canary (old_stk);
603
+
604
+ stk = old_stk->next ;
605
+
606
+ bool delete_stack = false ;
607
+ if (stk != NULL ) {
608
+ // Don't actually delete this stack. Save it to reuse later,
609
+ // preventing the pathological case where we repeatedly reallocate
610
+ // the stack for the next frame.
611
+ stk->prev = old_stk;
612
+ } else {
613
+ // This is the last stack, delete it.
614
+ delete_stack = true ;
615
+ }
616
+
617
+ // Delete the previous previous stack
618
+ if (old_stk->prev != NULL ) {
619
+ free_stack (old_stk->prev );
620
+ old_stk->prev = NULL ;
621
+ }
622
+
623
+ unconfig_valgrind_stack (old_stk);
624
+ if (delete_stack) {
625
+ free_stack (old_stk);
626
+ A (thread, total_stack_sz == 0 , " Stack size should be 0" );
627
+ }
628
+ }
635
629
636
630
void *
637
631
rust_task::next_stack (size_t stk_sz, void *args_addr, size_t args_sz) {
638
-
639
- stk_seg *stk_seg = new_stk (thread, this , stk_sz + args_sz);
640
- A (thread, stk_seg->end - (uintptr_t )stk_seg->data >= stk_sz + args_sz,
632
+ new_stack (stk_sz + args_sz);
633
+ A (thread, stk->end - (uintptr_t )stk->data >= stk_sz + args_sz,
641
634
" Did not receive enough stack" );
642
- uint8_t *new_sp = (uint8_t *)stk_seg ->end ;
635
+ uint8_t *new_sp = (uint8_t *)stk ->end ;
643
636
// Push the function arguments to the new stack
644
637
new_sp = align_down (new_sp - args_sz);
645
638
memcpy (new_sp, args_addr, args_sz);
@@ -651,7 +644,7 @@ rust_task::next_stack(size_t stk_sz, void *args_addr, size_t args_sz) {
651
644
652
645
void
653
646
rust_task::prev_stack () {
654
- del_stk ( this , stk );
647
+ del_stack ( );
655
648
A (thread, rust_task_thread::get_task () == this ,
656
649
" Recording the stack limit for the wrong thread" );
657
650
record_stack_limit ();
695
688
rust_task::reset_stack_limit () {
696
689
uintptr_t sp = get_sp ();
697
690
while (!sp_in_stk_seg (sp, stk)) {
698
- del_stk ( this , stk );
691
+ del_stack ( );
699
692
A (thread, stk != NULL , " Failed to find the current stack" );
700
693
}
701
694
record_stack_limit ();
0 commit comments