@@ -101,12 +101,16 @@ Caml_inline intnat caml_domain_alone(void)
101
101
int caml_domain_is_in_stw (void );
102
102
#endif
103
103
104
+ int caml_domain_terminating (caml_domain_state * );
105
+ int caml_domain_is_terminating (void );
106
+
104
107
int caml_try_run_on_all_domains_with_spin_work (
105
108
int sync ,
106
109
void (* handler )(caml_domain_state * , void * , int , caml_domain_state * * ),
107
110
void * data ,
108
111
void (* leader_setup )(caml_domain_state * ),
109
- void (* enter_spin_callback )(caml_domain_state * , void * ),
112
+ /* return nonzero if there may still be useful work to do while spinning */
113
+ int (* enter_spin_callback )(caml_domain_state * , void * ),
110
114
void * enter_spin_data );
111
115
int caml_try_run_on_all_domains (
112
116
void (* handler )(caml_domain_state * , void * , int , caml_domain_state * * ),
@@ -167,16 +171,54 @@ int caml_try_run_on_all_domains(
167
171
*/
168
172
169
173
170
- /* barriers */
171
- typedef uintnat barrier_status ;
172
- void caml_global_barrier (void );
173
- barrier_status caml_global_barrier_begin (void );
174
- int caml_global_barrier_is_final (barrier_status );
175
- void caml_global_barrier_end (barrier_status );
176
- int caml_global_barrier_num_domains (void );
174
+ /* Barriers */
177
175
178
- int caml_domain_terminating (caml_domain_state * );
179
- int caml_domain_is_terminating (void );
176
+ /* Get the number of parties expected to arrive into the barrier, i.e. the
177
+ number of domains participating in the STW section. In most cases the barrier
178
+ is used directly from an STW callback that already has the number of
179
+ participating domains at hand, which should be used instead. */
180
+ int caml_global_barrier_num_participating (void );
181
+
182
+ /* Unconditionally arrive at the barrier and wait for all parties,
183
+ [caml_global_barrier] below should be used instead. */
184
+ void caml_enter_global_barrier (int num_participating );
185
+ /* Arrive at the barrier and wait iff there is more than one party */
186
+ Caml_inline void caml_global_barrier (int num_participating ) {
187
+ if (num_participating != 1 ) caml_enter_global_barrier (num_participating );
188
+ }
189
+
190
+ typedef uintnat barrier_status ;
191
+ /* Arrive at the barrier; if we are the final party, immediately returns a
192
+ nonzero value to be passed to [caml_global_barrier_release_as_final]
193
+ later, otherwise blocks and returns zero. */
194
+ barrier_status caml_global_barrier_and_check_final (int num_participating );
195
+ /* Release the barrier with the given status */
196
+ void caml_global_barrier_release_as_final (barrier_status status );
197
+ /* Arrive at the global barrier and run the body if we are the final party.
198
+ Other threads will not be released from the barrier until the final party
199
+ finishes executing the body.
200
+
201
+ Example usage:
202
+
203
+ Caml_global_barrier_if_final(num_participating) {
204
+ do_something_in_final_domain();
205
+ }
206
+
207
+ Note: this expands to an [if] and [for] header, do not exit the body using
208
+ jumps or returns, and do not put an [else] immediately after.
209
+ */
210
+ #define Caml_global_barrier_if_final (num_participating ) \
211
+ /* fast path when alone */ \
212
+ int CAML_GENSYM(alone) = (num_participating) == 1; \
213
+ barrier_status CAML_GENSYM(b) = 0; \
214
+ if (CAML_GENSYM(alone) || \
215
+ (CAML_GENSYM(b) \
216
+ = caml_global_barrier_and_check_final(num_participating))) \
217
+ for (int CAML_GENSYM(continue) = 1; CAML_GENSYM(continue); \
218
+ /* release the barrier after the body has executed once */ \
219
+ ((CAML_GENSYM (alone ) ? (void )0 : \
220
+ caml_global_barrier_release_as_final (CAML_GENSYM (b ))), \
221
+ CAML_GENSYM (continue ) = 0 ))
180
222
181
223
#endif /* CAML_INTERNALS */
182
224
0 commit comments