Last active
June 27, 2020 00:06
-
-
Save d3x0r/36cee9fdf9d171bbedb0677188d4ed0a to your computer and use it in GitHub Desktop.
pthread_once emulation...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// best version | |
// would like to do CreateEvent in static initializer; but that's not a constant expression. | |
#define PTHREAD_ONCE_INIT { 0, 0 } | |
struct pthread_once { | |
HANDLE event; | |
volatile LONG inited; | |
}; | |
typedef struct pthread_once pthread_once_t; | |
static inline int | |
pthread_once(pthread_once_t *once, void (*cb) (void) ) { | |
if( !InterlockedExchange( &once->inited, 1 ) ) { | |
once->event = CreateEvent( NULL, TRUE, FALSE, NULL ); | |
cb(); | |
SetEvent( once->event ); | |
} | |
while( !once->event ) Sleep( 0 ); | |
DWORD rc = WaitForSingleObject( once->event, INFINITE ); | |
if( rc == WAIT_OBJECT_0 ) | |
return 0; | |
return 1; | |
} | |
//------------------------------------------------------------------- | |
// interlocked-exchange/spin-wait version | |
// modifies pthread_once and initializer | |
struct pthread_once { | |
volatile LONG inited; | |
volatile LONG initDone; | |
}; | |
typedef struct pthread_once pthread_once_t; | |
static inline BOOL CALLBACK | |
_pthread_once_win32_cb(PINIT_ONCE once, PVOID param, PVOID *context) | |
{ | |
void (*cb) (void) = param; | |
cb(); | |
return TRUE; | |
} | |
static inline void wait( int *on ) { | |
while( !on[0] ) Sleep(0); | |
} | |
#define pthread_once(o,cb) ( \ | |
(( !InterlockedExchange( &((o)[0]).inited, 1 ) )? \ | |
(cb(), \ | |
((o)[0]).initDone = 1):0), \ | |
wait( &((o)[0]).initDone ),0 \ | |
) | |
//------------------------------------------------------ | |
// simple one-time-runner macro; static is not allowed in expressions :( | |
#define pthread_once(o,cb) ( \ | |
static int inited, \ | |
static volatile int initDone, \ | |
( !InterlockedExchange( &inited, 1 ) )? \ | |
(cb(), \ | |
initDone = 1):0 \ | |
wait( &initDone ),0 \ | |
) | |
//----------------------------------------------------------- | |
// original method - non XP compatible. | |
struct pthread_once { | |
INIT_ONCE once; | |
}; | |
typedef struct pthread_once pthread_once_t; | |
static inline BOOL CALLBACK | |
_pthread_once_win32_cb(PINIT_ONCE once, PVOID param, PVOID *context) | |
{ | |
void (*cb) (void) = param; | |
cb(); | |
return TRUE; | |
} | |
static inline int | |
pthread_once(pthread_once_t *once, void (*cb) (void)) | |
{ | |
BOOL rc = InitOnceExecuteOnce(&once->once, _pthread_once_win32_cb, cb, NULL); | |
if (rc == 0) | |
return -1; | |
else | |
return 0; | |
} |
Well; as a consolation, one would expect code pointers to be less than or equal to data pointers (?)
A compiler with an issue like that would generate a warning probably on that line... casting data pointer to function pointer; but this is windows, so I don't really expect asymmetry?
Got it. I'm not very familiar with Windows, so I wasn't sure if that could even be an issue.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for sharing this gist. Is the cast at line 78 allowed? I mean, can't data pointers and function pointers have different sizes in some architectures?