-
Notifications
You must be signed in to change notification settings - Fork 207
Expand file tree
/
Copy pathcondition_win32.c
More file actions
160 lines (135 loc) · 5.26 KB
/
condition_win32.c
File metadata and controls
160 lines (135 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#include "azure_c_shared_utility/condition.h"
#include "windows.h"
#include "azure_c_shared_utility/xlogging.h"
#include "azure_c_shared_utility/gballoc.h"
MU_DEFINE_ENUM_STRINGS(COND_RESULT, COND_RESULT_VALUES);
typedef struct CONDITION_TAG
{
volatile LONG waiting_thread_count;
HANDLE event_handle;
}
CONDITION;
COND_HANDLE Condition_Init(void)
{
// Codes_SRS_CONDITION_18_002: [ Condition_Init shall create and return a CONDITION_HANDLE ]
CONDITION* cond = (CONDITION*)malloc(sizeof(CONDITION));
// Codes_SRS_CONDITION_18_008: [ Condition_Init shall return NULL if it fails to allocate the CONDITION_HANDLE ]
if (cond != NULL)
{
(void)memset(cond, 0, sizeof(CONDITION));
cond->event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
if (cond->event_handle == NULL)
{
LogError("CreateEvent failed with error %d", GetLastError());
free(cond);
cond = NULL;
}
else
{
/* Needed to emulate pthread_signal as we only signal the event when there are waiting threads */
cond->waiting_thread_count = 0;
}
}
else
{
LogError("Failed to allocate condition handle");
}
return (COND_HANDLE)cond;
}
COND_RESULT Condition_Post(COND_HANDLE handle)
{
COND_RESULT result;
if (handle == NULL)
{
LogError("Null argument handle passed to Condition_Post");
// Codes_SRS_CONDITION_18_001: [ Condition_Post shall return COND_INVALID_ARG if handle is NULL ]
result = COND_INVALID_ARG;
}
else
{
CONDITION* cond = (CONDITION*)handle;
/* Emulate pthreads signalling, by only unblocking *one* waiting thread if there is one waiting */
if (cond->waiting_thread_count == 0 || SetEvent(cond->event_handle))
{
// Codes_SRS_CONDITION_18_003: [ Condition_Post shall return COND_OK if it succcessfully posts the condition ]
result = COND_OK;
}
else
{
LogError("Failed SetEvent call with error %d", GetLastError());
result = COND_ERROR;
}
}
return result;
}
COND_RESULT Condition_Wait(COND_HANDLE handle, LOCK_HANDLE lock, int timeout_milliseconds)
{
COND_RESULT result;
// Codes_SRS_CONDITION_18_004: [ Condition_Wait shall return COND_INVALID_ARG if handle is NULL ]
// Codes_SRS_CONDITION_18_005: [ Condition_Wait shall return COND_INVALID_ARG if lock is NULL and timeout_milliseconds is 0 ]
// Codes_SRS_CONDITION_18_006: [ Condition_Wait shall return COND_INVALID_ARG if lock is NULL and timeout_milliseconds is not 0 ]
if (handle == NULL || lock == NULL)
{
result = COND_INVALID_ARG;
}
else
{
CONDITION* cond = (CONDITION*)handle;
/* Increment the waiting thread count, unlock the lock and wait */
cond->waiting_thread_count++;
if (Unlock(lock) == LOCK_OK)
{
DWORD wait_result;
// Codes_SRS_CONDITION_18_013: [ Condition_Wait shall accept relative timeouts ]
wait_result = WaitForSingleObject(cond->event_handle, timeout_milliseconds == 0 ? INFINITE : timeout_milliseconds);
/* If we unlocked ok, it means the lock handle is valid, lock must succeed since it wraps EnterCriticalSection */
(void)Lock(lock);
if (wait_result != WAIT_OBJECT_0 && wait_result != WAIT_TIMEOUT)
{
LogError("Failed wait, wait returned with %x", wait_result);
/* cond might be freed at this point, just return error and do not touch condition */
result = COND_ERROR;
}
else
{
/* To handle the chance of a race condition reset the event again when there are no more waiting threads */
if (--cond->waiting_thread_count == 0)
{
(void)ResetEvent(cond->event_handle);
}
if (wait_result == WAIT_TIMEOUT)
{
// Codes_SRS_CONDITION_18_011: [ Condition_Wait shall return COND_TIMEOUT if the condition is NOT triggered and timeout_milliseconds is not 0 ]
result = COND_TIMEOUT;
}
else
{
// Codes_SRS_CONDITION_18_012: [ Condition_Wait shall return COND_OK if the condition is triggered and timeout_milliseconds is not 0 ]
result = COND_OK;
}
}
}
else
{
cond->waiting_thread_count--;
LogError("Invalid lock passed which failed to unlock");
result = COND_ERROR;
}
}
return result;
}
void Condition_Deinit(COND_HANDLE handle)
{
// Codes_SRS_CONDITION_18_007: [ Condition_Deinit will not fail if handle is NULL ]
// Codes_SRS_CONDITION_18_009: [ Condition_Deinit will deallocate handle if it is not NULL
if (handle != NULL)
{
CONDITION* cond = (CONDITION*)handle;
(void)CloseHandle(cond->event_handle);
cond->event_handle = INVALID_HANDLE_VALUE;
free(cond);
}
}