Skip to content

Commit

Permalink
PR12579 (OS-based Synchronisation for Stop-the-World Sections): upstr…
Browse files Browse the repository at this point in the history
…eam 51491dd

(cherry picked from commit 20bd57a)
  • Loading branch information
mshinwell committed Aug 19, 2024
1 parent 5ec597b commit 0e0185e
Show file tree
Hide file tree
Showing 13 changed files with 1,044 additions and 348 deletions.
13 changes: 9 additions & 4 deletions ocaml/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,10 @@ AC_CHECK_HEADER([stdatomic.h], [AC_DEFINE([HAS_STDATOMIC_H])])

AC_CHECK_HEADER([sys/mman.h], [AC_DEFINE([HAS_SYS_MMAN_H])])

AS_CASE([$host],
[*-*-linux*],
[AC_CHECK_HEADER([linux/futex.h], [AC_DEFINE([HAS_LINUX_FUTEX_H])])])

# Checks for types

## off_t
Expand Down Expand Up @@ -2766,11 +2770,12 @@ ocamlc_cppflags="$common_cppflags $CPPFLAGS"

AS_CASE([$host],
[*-*-mingw32*],
[cclibs="$cclibs -lole32 -luuid -lversion"],
[cclibs="$cclibs -lole32 -luuid -lversion -lshlwapi -lsynchronization"],
[*-pc-windows],
[# For whatever reason, flexlink includes -ladvapi32 for mingw-w64, but
# doesn't include advapi32.lib for MSVC
cclibs="$cclibs ole32.lib uuid.lib advapi32.lib version.lib"])
[# For whatever reason, flexlink includes -ladvapi32 and -lshell32 for
# mingw-w64, but doesn't include advapi32.lib and shell32.lib for MSVC
cclibs="$cclibs ole32.lib uuid.lib advapi32.lib shell32.lib version.lib \
shlwapi.lib synchronization.lib"])

AC_CONFIG_COMMANDS_PRE([cclibs="$cclibs $mathlib $DLLIBS $PTHREAD_LIBS"])

Expand Down
62 changes: 52 additions & 10 deletions ocaml/runtime/caml/domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,16 @@ Caml_inline intnat caml_domain_alone(void)
int caml_domain_is_in_stw(void);
#endif

int caml_domain_terminating(caml_domain_state *);
int caml_domain_is_terminating(void);

int caml_try_run_on_all_domains_with_spin_work(
int sync,
void (*handler)(caml_domain_state*, void*, int, caml_domain_state**),
void* data,
void (*leader_setup)(caml_domain_state*),
void (*enter_spin_callback)(caml_domain_state*, void*),
/* return nonzero if there may still be useful work to do while spinning */
int (*enter_spin_callback)(caml_domain_state*, void*),
void* enter_spin_data);
int caml_try_run_on_all_domains(
void (*handler)(caml_domain_state*, void*, int, caml_domain_state**),
Expand Down Expand Up @@ -167,16 +171,54 @@ int caml_try_run_on_all_domains(
*/


/* barriers */
typedef uintnat barrier_status;
void caml_global_barrier(void);
barrier_status caml_global_barrier_begin(void);
int caml_global_barrier_is_final(barrier_status);
void caml_global_barrier_end(barrier_status);
int caml_global_barrier_num_domains(void);
/* Barriers */

int caml_domain_terminating(caml_domain_state *);
int caml_domain_is_terminating(void);
/* Get the number of parties expected to arrive into the barrier, i.e. the
number of domains participating in the STW section. In most cases the barrier
is used directly from an STW callback that already has the number of
participating domains at hand, which should be used instead. */
int caml_global_barrier_num_participating(void);

/* Unconditionally arrive at the barrier and wait for all parties,
[caml_global_barrier] below should be used instead. */
void caml_enter_global_barrier(int num_participating);
/* Arrive at the barrier and wait iff there is more than one party */
Caml_inline void caml_global_barrier(int num_participating) {
if (num_participating != 1) caml_enter_global_barrier(num_participating);
}

typedef uintnat barrier_status;
/* Arrive at the barrier; if we are the final party, immediately returns a
nonzero value to be passed to [caml_global_barrier_release_as_final]
later, otherwise blocks and returns zero. */
barrier_status caml_global_barrier_and_check_final(int num_participating);
/* Release the barrier with the given status */
void caml_global_barrier_release_as_final(barrier_status status);
/* Arrive at the global barrier and run the body if we are the final party.
Other threads will not be released from the barrier until the final party
finishes executing the body.
Example usage:
Caml_global_barrier_if_final(num_participating) {
do_something_in_final_domain();
}
Note: this expands to an [if] and [for] header, do not exit the body using
jumps or returns, and do not put an [else] immediately after.
*/
#define Caml_global_barrier_if_final(num_participating) \
/* fast path when alone */ \
int CAML_GENSYM(alone) = (num_participating) == 1; \
barrier_status CAML_GENSYM(b) = 0; \
if (CAML_GENSYM(alone) || \
(CAML_GENSYM(b) \
= caml_global_barrier_and_check_final(num_participating))) \
for (int CAML_GENSYM(continue) = 1; CAML_GENSYM(continue); \
/* release the barrier after the body has executed once */ \
((CAML_GENSYM(alone) ? (void)0 : \
caml_global_barrier_release_as_final(CAML_GENSYM(b))), \
CAML_GENSYM(continue) = 0))

#endif /* CAML_INTERNALS */

Expand Down
2 changes: 1 addition & 1 deletion ocaml/runtime/caml/major_gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Caml_inline int caml_marking_started(void) {
return caml_gc_phase != Phase_sweep_main;
}

intnat caml_opportunistic_major_work_available (void);
intnat caml_opportunistic_major_work_available (caml_domain_state*);
void caml_opportunistic_major_collection_slice (intnat);
/* auto-triggered slice from within the GC */
#define AUTO_TRIGGERED_MAJOR_SLICE -1
Expand Down
5 changes: 5 additions & 0 deletions ocaml/runtime/caml/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,11 @@ CAMLextern int caml_snwprintf(wchar_t * buf,
# endif
#endif

/* Generate a named symbol that is unique within the current macro expansion */
#define CAML_GENSYM_3(name, l) caml__##name##_##l
#define CAML_GENSYM_2(name, l) CAML_GENSYM_3(name, l)
#define CAML_GENSYM(name) CAML_GENSYM_2(name, __LINE__)

#endif /* CAML_INTERNALS */

/* The [backtrace_slot] type represents values stored in
Expand Down
Loading

0 comments on commit 0e0185e

Please sign in to comment.