1 /* *****************************************************************
3 * Copyright 2017 Microsoft
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 ******************************************************************/
22 * This file implements Event object for allowing threads to wait on.
26 #include "oic_malloc.h"
30 #include "iotivity_debug.h"
38 * Logging tag for module name
40 #define TAG "OIC_EVENT"
42 typedef struct oc_event_t
44 /* Mutex for protecting the members. */
46 /* The conditional variable to wait on. */
48 /* Whether the event is signaled. */
52 oc_event oc_event_new(void)
54 oc_event event = (oc_event)OICCalloc(1, sizeof(oc_event_t));
57 OIC_LOG(ERROR, TAG, "Failed to allocate oc_event");
61 event->mutex = oc_mutex_new();
62 event->cond = oc_cond_new();
63 event->signaled = false;
65 if (!event->mutex || !event->cond)
74 void oc_event_free(oc_event event)
78 oc_mutex_free(event->mutex);
79 oc_cond_free(event->cond);
84 void oc_event_wait(oc_event event)
86 OC_VERIFY(OC_WAIT_SUCCESS == oc_event_wait_for(event, UINT32_MAX));
89 OCWaitResult_t oc_event_wait_for(oc_event event, uint32_t milliseconds)
91 bool timedOut = false;
92 oc_mutex_assert_owner(event->mutex, false);
93 oc_mutex_lock(event->mutex);
97 if (0 != milliseconds)
99 const uint64_t startTime = OICGetCurrentTime(TIME_IN_MS);
100 uint64_t remaining = milliseconds;
101 // This while loop is to filter spurious wakeups caused by conditional variable.
102 while (!event->signaled)
104 oc_mutex_assert_owner(event->mutex, true);
105 OCWaitResult_t waitResult = oc_cond_wait_for(event->cond, event->mutex,
106 (remaining * US_PER_MS));
107 if (OC_WAIT_TIMEDOUT == waitResult)
112 assert(OC_WAIT_SUCCESS == waitResult);
114 // Not timed out, see if the event is in signaled state and reset it.
121 // Not timed out and not signaled => spurious wakeup, see if we ran out of time.
122 const uint64_t elapsed = (OICGetCurrentTime(TIME_IN_MS) - startTime);
123 if (elapsed >= (uint64_t)milliseconds)
129 // Encountered spurious wakeup and still has time to wait, recalculate the
130 // remaining time and wait again.
131 // Spurious wakeup: depending on the platform, waiting on a Condition Variable can
132 // occasionally (though rarely) return from the wait state even when the condition
133 // isn't set, so we always need to revalidate the state in a loop here.
134 remaining = (uint64_t)milliseconds - elapsed;
139 // Zero timeout provided and the event has not been signaled.
143 oc_mutex_assert_owner(event->mutex, true);
144 event->signaled = false;
145 oc_mutex_unlock(event->mutex);
146 return timedOut ? OC_WAIT_TIMEDOUT : OC_WAIT_SUCCESS;
149 void oc_event_signal(oc_event event)
151 oc_mutex_assert_owner(event->mutex, false);
152 oc_mutex_lock(event->mutex);
153 if (!event->signaled)
155 event->signaled = true;
156 oc_cond_signal(event->cond);
158 oc_mutex_unlock(event->mutex);