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