1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2009-2016. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 /*
22 * Author: Rickard Green
23 */
24
25 #define ETHR_INLINE_FUNC_NAME_(X) X ## __
26 #define ETHR_EVENT_IMPL__
27
28 #include "ethread.h"
29 #include "ethr_internal.h"
30
31 /* --- Windows implementation of thread events ------------------------------ */
32
33 void
ethr_init_event__(void)34 ethr_init_event__(void)
35 {
36
37 }
38
39 int
ethr_event_init(ethr_event * e)40 ethr_event_init(ethr_event *e)
41 {
42 ethr_atomic32_init(&e->state, ETHR_EVENT_OFF__);
43 e->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
44 if (e->handle == INVALID_HANDLE_VALUE)
45 return ethr_win_get_errno__();
46 return 0;
47 }
48
49 int
ethr_event_prepare_timed(ethr_event * e)50 ethr_event_prepare_timed(ethr_event *e)
51 {
52 return 0;
53 }
54
55 int
ethr_event_destroy(ethr_event * e)56 ethr_event_destroy(ethr_event *e)
57 {
58 BOOL res = CloseHandle(e->handle);
59 return res == 0 ? ethr_win_get_errno__() : 0;
60 }
61
62 void
ethr_event_set(ethr_event * e)63 ethr_event_set(ethr_event *e)
64 {
65 ethr_event_set__(e);
66 }
67
68 void
ethr_event_reset(ethr_event * e)69 ethr_event_reset(ethr_event *e)
70 {
71 ethr_event_reset__(e);
72 }
73
74 static ETHR_INLINE int
wait(ethr_event * e,int spincount,ethr_sint64_t timeout)75 wait(ethr_event *e, int spincount, ethr_sint64_t timeout)
76 {
77 DWORD code, tmo;
78 int sc, res, until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
79
80 if (timeout < 0)
81 tmo = INFINITE;
82 else if (timeout == 0) {
83 ethr_sint32_t state = ethr_atomic32_read(&e->state);
84 if (state == ETHR_EVENT_ON__) {
85 ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);
86 return 0;
87 }
88 return ETIMEDOUT;
89 }
90 else {
91 /*
92 * Timeout in nano-seconds, but we can only
93 * wait for milli-seconds...
94 */
95 tmo = (DWORD) (timeout - 1) / (1000*1000) + 1;
96 }
97
98 if (spincount < 0)
99 ETHR_FATAL_ERROR__(EINVAL);
100
101 sc = spincount;
102
103 while (1) {
104 ethr_sint32_t state;
105 while (1) {
106 state = ethr_atomic32_read(&e->state);
107 if (state == ETHR_EVENT_ON__) {
108 ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);
109 return 0;
110 }
111 if (sc == 0)
112 break;
113 sc--;
114 ETHR_SPIN_BODY;
115 if (--until_yield == 0) {
116 until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
117 res = ETHR_YIELD();
118 if (res != 0)
119 ETHR_FATAL_ERROR__(res);
120 }
121 }
122
123 if (state != ETHR_EVENT_OFF_WAITER__) {
124 state = ethr_atomic32_cmpxchg(&e->state,
125 ETHR_EVENT_OFF_WAITER__,
126 ETHR_EVENT_OFF__);
127 if (state == ETHR_EVENT_ON__)
128 return 0;
129 ETHR_ASSERT(state == ETHR_EVENT_OFF__);
130 }
131
132 code = WaitForSingleObject(e->handle, tmo);
133 if (code == WAIT_TIMEOUT)
134 return ETIMEDOUT;
135 if (code != WAIT_OBJECT_0)
136 ETHR_FATAL_ERROR__(ethr_win_get_errno__());
137 }
138
139 }
140
141 int
ethr_event_wait(ethr_event * e)142 ethr_event_wait(ethr_event *e)
143 {
144 return wait(e, 0, -1);
145 }
146
147 int
ethr_event_swait(ethr_event * e,int spincount)148 ethr_event_swait(ethr_event *e, int spincount)
149 {
150 return wait(e, spincount, -1);
151 }
152
153 int
ethr_event_twait(ethr_event * e,ethr_sint64_t timeout)154 ethr_event_twait(ethr_event *e, ethr_sint64_t timeout)
155 {
156 return wait(e, 0, timeout);
157 }
158
159 int
ethr_event_stwait(ethr_event * e,int spincount,ethr_sint64_t timeout)160 ethr_event_stwait(ethr_event *e, int spincount, ethr_sint64_t timeout)
161 {
162 return wait(e, spincount, timeout);
163 }
164