// -*- Mode: C -*- // // Cforall Version 1.0.0 Copyright (C) 2022 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // barrier.hfa -- simple barrier implemented using a monitor // // Author : Peter A. Buhr // Created On : Sun Nov 10 08:07:35 2024 // Last Modified By : Peter A. Buhr // Last Modified On : Fri Oct 31 09:22:14 2025 // Update Count : 69 // #pragma once #include #include // Plan 9 inheritance does not work with monitors. Two monitor locks are created. typedef void (* barrier_fptr_t)( ... ); // like C++, () => void and ... => C () monitor barrier { size_t group$, arrivals$; // group size, arrival counter (backward) condition c$; // wait for group to form barrier_fptr_t callback$; // global callback void * arg$; // global callback argument }; static inline void ?{}( barrier & b, ssize_t group, barrier_fptr_t callback, void * arg ) with ( b ) { [group$, arrivals$] = group; [callback$, arg$] = [callback, arg]; } static inline void ?{}( barrier & b, ssize_t group ) { (b){ group, 0p, 0p }; } // call base constructor static inline ssize_t waiters( barrier & b ) with( b ) { return group$ - arrivals$; } static inline ssize_t total( barrier & b ) with( b ) { return group$; } // Returns a value indicating the reverse order the threads arrived, i.e., the Gth thread returns 0 (and does not // block). olock is an optional mutex lock held by the called and atomically released and block. callback is an // optional function that is called by the Gth thread before unblocking the other threads. arg is an optional (void *) // argument passed to the callback. // Barrier is a monitor => implicit mutual exclusion. static inline ssize_t block( barrier & mutex b, owner_lock & olock, barrier_fptr_t callback, void * arg ) with( b ) { arrivals$ -= 1; // prefix decrement so last is 0 not 1 typeof( arrivals$ ) arrived = arrivals$; // note arrival order if ( arrivals$ != 0 ) { // wait for group to form if ( &olock != 0p ) unlock( olock ); // if lock specified, release it wait( c$ ); // DO NOT REACQUIRE LOCK TO ALLOW BARGING PREVENTION } else { // group formed if ( callback ) callback( arg ); // if callback specified, safe to call with argument else if ( callback$ ) callback$( arg$ ); // if callback specified, safe to call with argument signal_all( c$ ); // unblock group arrivals$ = group$; // reset } // if return arrived; // return arrival order } static inline ssize_t block( barrier & b ) { return block( b, *0p, 0p, 0p ); } static inline ssize_t block( barrier & b, owner_lock & olock ) { return block( b, olock, 0p, 0p ); } static inline ssize_t block( barrier & b, barrier_fptr_t callback ) { return block( b, *0p, callback, 0p ); } static inline ssize_t block( barrier & b, barrier_fptr_t callback, void * arg ) { return block( b, *0p, callback, arg ); } static inline ssize_t block( barrier & b, owner_lock & olock, barrier_fptr_t callback ) { return block( b, olock, callback, 0p ); }