/*++ Copyright (c) Microsoft. All rights reserved. Module Name: lxtevent.c Abstract: This file contains synchronization event primitive support. --*/ #include // // Synchronization event usable for synchronizing threads and forked processes. // typedef struct _LXT_SYNCHRONIZATION_EVENT { pthread_cond_t WaitConditionalVariable; pthread_condattr_t ConditionVariableAttribute; pthread_mutex_t Lock; pthread_mutexattr_t LockAttribute; int Ready; int Fail; } LXT_SYNCHRONIZATION_EVENT, *PLXT_SYNCHRONIZATION_EVENT; int LxtSynchronizationEventClear(PLXT_SYNCHRONIZATION_EVENT Event); int LxtSynchronizationEventDestroy(PLXT_SYNCHRONIZATION_EVENT* Event); int LxtSynchronizationEventFail(PLXT_SYNCHRONIZATION_EVENT Event); int LxtSynchronizationEventInit(PLXT_SYNCHRONIZATION_EVENT* Event); int LxtSynchronizationEventReset(PLXT_SYNCHRONIZATION_EVENT Event); int LxtSynchronizationEventSet(PLXT_SYNCHRONIZATION_EVENT Event); int LxtSynchronizationEventWait(PLXT_SYNCHRONIZATION_EVENT Event); // // Synchronization point based on synchronization event. // #define LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(_ChildPidVariable_) \ PLXT_SYNCHRONIZATION_EVENT LxtSync##_ChildPidVariable_##Parent; \ PLXT_SYNCHRONIZATION_EVENT LxtSync##_ChildPidVariable_##Child; #define LXT_SYNCHRONIZATION_POINT_DECLARE_FOR_STATIC(_ChildPidVariable_) \ static PLXT_SYNCHRONIZATION_EVENT LxtSync##_ChildPidVariable_##Parent; \ static PLXT_SYNCHRONIZATION_EVENT LxtSync##_ChildPidVariable_##Child; #define LXT_SYNCHRONIZATION_POINT_INIT_SYNCVARS(_ParentVar_, _ChildVar_) \ (_ParentVar_) = NULL; \ (_ChildVar_) = NULL; \ LxtCheckResult(LxtSynchronizationEventInit(&_ParentVar_)); \ LxtCheckResult(LxtSynchronizationEventInit(&_ChildVar_)); #define LXT_SYNCHRONIZATION_POINT_INIT_FOR(_ChildPidVariable_) \ LXT_SYNCHRONIZATION_POINT_INIT_SYNCVARS(LxtSync##_ChildPidVariable_##Parent, LxtSync##_ChildPidVariable_##Child) #define LXT_SYNCHRONIZATION_POINT_INIT() LXT_SYNCHRONIZATION_POINT_INIT_FOR(ChildPid) #define LXT_SYNCHRONIZATION_POINT_DESTROY_SYNCVARS(_ParentVar_, _ChildVar_) \ LxtSynchronizationEventDestroy(&(_ParentVar_)); \ LxtSynchronizationEventDestroy(&(_ChildVar_)); #define LXT_SYNCHRONIZATION_POINT_DESTROY_FOR(_ChildPidVariable_) \ LXT_SYNCHRONIZATION_POINT_DESTROY_SYNCVARS(LxtSync##_ChildPidVariable_##Parent, LxtSync##_ChildPidVariable_##Child) #define LXT_SYNCHRONIZATION_POINT_DESTROY() LXT_SYNCHRONIZATION_POINT_DESTROY_FOR(ChildPid) #define LXT_SYNCHRONIZATION_POINT_START_SYNCVARS(_ParentVar_, _ChildVar_) \ LxtSynchronizationEventReset(_ChildVar_); \ LxtSynchronizationEventReset(_ParentVar_); #define LXT_SYNCHRONIZATION_POINT_START_FOR(_ChildPidVariable_) \ LXT_SYNCHRONIZATION_POINT_START_SYNCVARS(LxtSync##_ChildPidVariable_##Child, LxtSync##_ChildPidVariable_##Parent) #define LXT_SYNCHRONIZATION_POINT_START() LXT_SYNCHRONIZATION_POINT_START_FOR(ChildPid) #define LXT_SYNCHRONIZATION_POINT_END_SYNCVARS(_ChildId_, _ParentVar_, _ChildVar_, _Destroy_) \ if (((_ChildId_) >= 0) && (Result < 0)) \ { \ LxtLogError("Failing synchronization points."); \ LxtSynchronizationEventFail(_ChildVar_); \ LxtSynchronizationEventFail(_ParentVar_); \ } \ if ((_ChildId_) > 0) \ { \ if (TEMP_FAILURE_RETRY(waitpid((_ChildId_), &Status, 0)) >= 0) \ { \ if (!WIFEXITED(Status)) \ { \ LxtLogInfo("Child exited uncleanly (Child = %d, Status = %x)", (_ChildId_), Status); \ Result = LXT_RESULT_FAILURE; \ } \ else \ { \ Result = (int)(char)WEXITSTATUS(Status); \ } \ } \ else \ { \ Result = errno; \ LxtLogInfo("Failed wait on child %d with errno %d", (_ChildId_), Result); \ } \ if ((Result == LXT_RESULT_SUCCESS) && ((_ChildVar_)->Fail == 1)) \ { \ LxtLogInfo("Child failed"); \ Result = LXT_RESULT_FAILURE; \ } \ if ((_Destroy_) != FALSE) \ { \ LXT_SYNCHRONIZATION_POINT_DESTROY_SYNCVARS(_ParentVar_, _ChildVar_) \ } \ } \ else if ((_ChildId_) == 0) \ { \ _exit(Result); \ } #define LXT_SYNCHRONIZATION_POINT_END_FOR(_ChildPidVariable_, _Destroy_) \ LXT_SYNCHRONIZATION_POINT_END_SYNCVARS((_ChildPidVariable_), LxtSync##_ChildPidVariable_##Parent, LxtSync##_ChildPidVariable_##Child, _Destroy_) #define LXT_SYNCHRONIZATION_POINT_END() LXT_SYNCHRONIZATION_POINT_END_FOR(ChildPid, FALSE) #define LXT_SYNCHRONIZATION_POINT_PTHREAD_END_THREAD_SYNCVARS(_ParentVar_, _ChildVar_) \ if (Result < 0) \ { \ LxtLogError("Failing synchronization points."); \ LxtSynchronizationEventFail(_ChildVar_); \ LxtSynchronizationEventFail(_ParentVar_); \ } #define LXT_SYNCHRONIZATION_POINT_PTHREAD_END_THREAD_FOR(_SyncIdVariable_) \ LXT_SYNCHRONIZATION_POINT_PTHREAD_END_THREAD_SYNCVARS(LxtSync##_SyncIdVariable_##Parent, LxtSync##_SyncIdVariable_##Child) #define LXT_SYNCHRONIZATION_POINT_PTHREAD_END_THREAD() LXT_SYNCHRONIZATION_POINT_PTHREAD_END_THREAD_FOR(ChildPid) #define LXT_SYNCHRONIZATION_POINT_PTHREAD_END_PARENT_SYNCVARS(_ThreadId_, _ParentVar_, _ChildVar_) \ if (Result < 0) \ { \ LxtLogError("Failing synchronization points."); \ LxtSynchronizationEventFail(_ChildVar_); \ LxtSynchronizationEventFail(_ParentVar_); \ } \ if (((_ThreadId_) > 0) && (pthread_join((_ThreadId_), &Status) == 0)) \ { \ if (Status != 0) \ { \ LxtLogInfo("Thread exited uncleanly (Thread = %d, Status = %x)", (_ThreadId_), (int)(long)Status); \ Result = LXT_RESULT_FAILURE; \ } \ } \ else if ((_ThreadId_) > 0) \ { \ Result = errno; \ LxtLogInfo("Failed wait on thread %d with errno %d", (_ThreadId_), Result); \ } \ if ((Result == LXT_RESULT_SUCCESS) && ((_ChildVar_)->Fail == 1)) \ { \ LxtLogInfo("Thread failed"); \ Result = LXT_RESULT_FAILURE; \ } #define LXT_SYNCHRONIZATION_POINT_PTHREAD_END_PARENT_FOR(_ThreadId_, _SyncIdVariable_) \ LXT_SYNCHRONIZATION_POINT_PTHREAD_END_PARENT_SYNCVARS((_ThreadId_), LxtSync##_SyncIdVariable_##Parent, LxtSync##_SyncIdVariable_##Child) #define LXT_SYNCHRONIZATION_POINT_PTHREAD_END_PARENT(_ThreadId_) \ LXT_SYNCHRONIZATION_POINT_PTHREAD_END_PARENT_FOR(_ThreadId_, ChildPid) #define LXT_SYNCHRONIZATION_POINT_CLEAR_FOR(_ChildPidVariable_) \ if (Result < 0) \ { \ LxtCheckResult(LxtSynchronizationEventClear(LxtSync##_ChildPidVariable_##Child)); \ LxtCheckResult(LxtSynchronizationEventClear(LxtSync##_ChildPidVariable_##Parent)); \ } #define LXT_SYNCHRONIZATION_POINT_CLEAR() LXT_SYNCHRONIZATION_POINT_CLEAR_FOR(ChildPid) #define LXT_SYNCHRONIZATION_POINT_SYNCVARS(_IsChild_, _ParentVar_, _ChildVar_) \ if ((_IsChild_) != FALSE) \ { \ LxtCheckResult(LxtSynchronizationEventWait(_ChildVar_)); \ LxtCheckResult(LxtSynchronizationEventClear(_ChildVar_)); \ LxtCheckResult(LxtSynchronizationEventSet(_ParentVar_)); \ } \ else \ { \ LxtCheckResult(LxtSynchronizationEventSet(_ChildVar_)); \ LxtCheckResult(LxtSynchronizationEventWait(_ParentVar_)); \ LxtCheckResult(LxtSynchronizationEventClear(_ParentVar_)); \ } #define LXT_SYNCHRONIZATION_POINT_CHILD_FOR(_ChildPidVariable_) \ LXT_SYNCHRONIZATION_POINT_SYNCVARS(TRUE, LxtSync##_ChildPidVariable_##Parent, LxtSync##_ChildPidVariable_##Child) #define LXT_SYNCHRONIZATION_POINT_PARENT_FOR(_ChildPidVariable_) \ LXT_SYNCHRONIZATION_POINT_SYNCVARS(FALSE, LxtSync##_ChildPidVariable_##Parent, LxtSync##_ChildPidVariable_##Child) #define LXT_SYNCHRONIZATION_POINT_FOR(_ChildPidVariable_) \ if ((_ChildPidVariable_) == 0) \ { \ LXT_SYNCHRONIZATION_POINT_CHILD_FOR(_ChildPidVariable_); \ } \ else \ { \ LXT_SYNCHRONIZATION_POINT_PARENT_FOR(_ChildPidVariable_); \ } #define LXT_SYNCHRONIZATION_POINT_CHILD() LXT_SYNCHRONIZATION_POINT_CHILD_FOR(ChildPid) #define LXT_SYNCHRONIZATION_POINT_PARENT() LXT_SYNCHRONIZATION_POINT_PARENT_FOR(ChildPid) #define LXT_SYNCHRONIZATION_POINT() LXT_SYNCHRONIZATION_POINT_FOR(ChildPid); // // Declare global synchronization values for common ChildPid variable. // LXT_SYNCHRONIZATION_POINT_DECLARE_FOR_STATIC(ChildPid)