mfmediaengine: Remove unnecessary import library.
[wine.git] / dlls / quartz / systemclock.c
blobf579ae754eaec8aa33d1ce530f787a45305b12cb
1 /*
2 * Implementation of IReferenceClock
4 * Copyright 2004 Raphael Junqueira
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "quartz_private.h"
23 #include "wine/debug.h"
24 #include <assert.h>
26 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
28 static int cookie_counter;
30 struct advise_sink
32 struct list entry;
33 HANDLE handle;
34 REFERENCE_TIME due_time, period;
35 int cookie;
38 struct system_clock
40 IReferenceClock IReferenceClock_iface;
41 IUnknown IUnknown_inner;
42 IUnknown *outer_unk;
43 LONG refcount;
45 BOOL thread_created, thread_stopped;
46 HANDLE thread;
47 LARGE_INTEGER frequency;
48 REFERENCE_TIME last_time;
49 CRITICAL_SECTION cs;
50 CONDITION_VARIABLE cv;
52 struct list sinks;
55 static REFERENCE_TIME get_current_time(const struct system_clock *clock)
57 LARGE_INTEGER time;
59 QueryPerformanceCounter(&time);
60 return (time.QuadPart * 1000) / clock->frequency.QuadPart * 10000;
63 static inline struct system_clock *impl_from_IUnknown(IUnknown *iface)
65 return CONTAINING_RECORD(iface, struct system_clock, IUnknown_inner);
68 static HRESULT WINAPI system_clock_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out)
70 struct system_clock *clock = impl_from_IUnknown(iface);
71 TRACE("clock %p, iid %s, out %p.\n", clock, debugstr_guid(iid), out);
73 if (IsEqualGUID(iid, &IID_IUnknown))
74 *out = iface;
75 else if (IsEqualGUID(iid, &IID_IReferenceClock))
76 *out = &clock->IReferenceClock_iface;
77 else
79 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
80 *out = NULL;
81 return E_NOINTERFACE;
84 IUnknown_AddRef((IUnknown *)*out);
85 return S_OK;
88 static ULONG WINAPI system_clock_inner_AddRef(IUnknown *iface)
90 struct system_clock *clock = impl_from_IUnknown(iface);
91 ULONG refcount = InterlockedIncrement(&clock->refcount);
93 TRACE("%p increasing refcount to %u.\n", clock, refcount);
95 return refcount;
98 static ULONG WINAPI system_clock_inner_Release(IUnknown *iface)
100 struct system_clock *clock = impl_from_IUnknown(iface);
101 ULONG refcount = InterlockedDecrement(&clock->refcount);
102 struct advise_sink *sink, *cursor;
104 TRACE("%p decreasing refcount to %u.\n", clock, refcount);
106 if (!refcount)
108 if (clock->thread)
110 EnterCriticalSection(&clock->cs);
111 clock->thread_stopped = TRUE;
112 LeaveCriticalSection(&clock->cs);
113 WakeConditionVariable(&clock->cv);
114 WaitForSingleObject(clock->thread, INFINITE);
115 CloseHandle(clock->thread);
118 LIST_FOR_EACH_ENTRY_SAFE(sink, cursor, &clock->sinks, struct advise_sink, entry)
120 list_remove(&sink->entry);
121 heap_free(sink);
124 clock->cs.DebugInfo->Spare[0] = 0;
125 DeleteCriticalSection(&clock->cs);
126 heap_free(clock);
128 return refcount;
131 static const IUnknownVtbl system_clock_inner_vtbl =
133 system_clock_inner_QueryInterface,
134 system_clock_inner_AddRef,
135 system_clock_inner_Release,
138 static inline struct system_clock *impl_from_IReferenceClock(IReferenceClock *iface)
140 return CONTAINING_RECORD(iface, struct system_clock, IReferenceClock_iface);
143 static DWORD WINAPI SystemClockAdviseThread(void *param)
145 struct system_clock *clock = param;
146 struct advise_sink *sink, *cursor;
147 REFERENCE_TIME current_time;
149 TRACE("Starting advise thread for clock %p.\n", clock);
151 for (;;)
153 DWORD timeout = INFINITE;
155 EnterCriticalSection(&clock->cs);
157 current_time = get_current_time(clock);
159 LIST_FOR_EACH_ENTRY_SAFE(sink, cursor, &clock->sinks, struct advise_sink, entry)
161 if (sink->due_time <= current_time)
163 if (sink->period)
165 DWORD periods = ((current_time - sink->due_time) / sink->period) + 1;
166 ReleaseSemaphore(sink->handle, periods, NULL);
167 sink->due_time += periods * sink->period;
169 else
171 SetEvent(sink->handle);
172 list_remove(&sink->entry);
173 heap_free(sink);
174 continue;
178 timeout = min(timeout, (sink->due_time - current_time) / 10000);
181 SleepConditionVariableCS(&clock->cv, &clock->cs, timeout);
182 if (clock->thread_stopped)
184 LeaveCriticalSection(&clock->cs);
185 return 0;
187 LeaveCriticalSection(&clock->cs);
191 static HRESULT add_sink(struct system_clock *clock, DWORD_PTR handle,
192 REFERENCE_TIME due_time, REFERENCE_TIME period, DWORD_PTR *cookie)
194 struct advise_sink *sink;
196 if (!handle)
197 return E_INVALIDARG;
199 if (!cookie)
200 return E_POINTER;
202 if (!(sink = heap_alloc_zero(sizeof(*sink))))
203 return E_OUTOFMEMORY;
205 sink->handle = (HANDLE)handle;
206 sink->due_time = due_time;
207 sink->period = period;
208 sink->cookie = InterlockedIncrement(&cookie_counter);
209 *cookie = sink->cookie;
211 EnterCriticalSection(&clock->cs);
212 list_add_tail(&clock->sinks, &sink->entry);
213 LeaveCriticalSection(&clock->cs);
215 if (!InterlockedCompareExchange(&clock->thread_created, TRUE, FALSE))
217 clock->thread = CreateThread(NULL, 0, SystemClockAdviseThread, clock, 0, NULL);
219 WakeConditionVariable(&clock->cv);
221 return S_OK;
224 static HRESULT WINAPI SystemClockImpl_QueryInterface(IReferenceClock *iface, REFIID iid, void **out)
226 struct system_clock *clock = impl_from_IReferenceClock(iface);
227 return IUnknown_QueryInterface(clock->outer_unk, iid, out);
230 static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock *iface)
232 struct system_clock *clock = impl_from_IReferenceClock(iface);
233 return IUnknown_AddRef(clock->outer_unk);
236 static ULONG WINAPI SystemClockImpl_Release(IReferenceClock *iface)
238 struct system_clock *clock = impl_from_IReferenceClock(iface);
239 return IUnknown_Release(clock->outer_unk);
242 static HRESULT WINAPI SystemClockImpl_GetTime(IReferenceClock *iface, REFERENCE_TIME *time)
244 struct system_clock *clock = impl_from_IReferenceClock(iface);
245 REFERENCE_TIME ret;
246 HRESULT hr;
248 if (!time) {
249 return E_POINTER;
252 ret = get_current_time(clock);
254 EnterCriticalSection(&clock->cs);
256 hr = (ret == clock->last_time) ? S_FALSE : S_OK;
257 *time = clock->last_time = ret;
259 LeaveCriticalSection(&clock->cs);
261 TRACE("clock %p, time %p, returning %s.\n", clock, time, debugstr_time(ret));
262 return hr;
265 static HRESULT WINAPI SystemClockImpl_AdviseTime(IReferenceClock *iface,
266 REFERENCE_TIME base, REFERENCE_TIME offset, HEVENT event, DWORD_PTR *cookie)
268 struct system_clock *clock = impl_from_IReferenceClock(iface);
270 TRACE("clock %p, base %s, offset %s, event %#lx, cookie %p.\n",
271 clock, debugstr_time(base), debugstr_time(offset), event, cookie);
273 if (base + offset <= 0)
274 return E_INVALIDARG;
276 return add_sink(clock, event, base + offset, 0, cookie);
279 static HRESULT WINAPI SystemClockImpl_AdvisePeriodic(IReferenceClock* iface,
280 REFERENCE_TIME start, REFERENCE_TIME period, HSEMAPHORE semaphore, DWORD_PTR *cookie)
282 struct system_clock *clock = impl_from_IReferenceClock(iface);
284 TRACE("clock %p, start %s, period %s, semaphore %#lx, cookie %p.\n",
285 clock, debugstr_time(start), debugstr_time(period), semaphore, cookie);
287 if (start <= 0 || period <= 0)
288 return E_INVALIDARG;
290 return add_sink(clock, semaphore, start, period, cookie);
293 static HRESULT WINAPI SystemClockImpl_Unadvise(IReferenceClock *iface, DWORD_PTR cookie)
295 struct system_clock *clock = impl_from_IReferenceClock(iface);
296 struct advise_sink *sink;
298 TRACE("clock %p, cookie %#lx.\n", clock, cookie);
300 EnterCriticalSection(&clock->cs);
302 LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct advise_sink, entry)
304 if (sink->cookie == cookie)
306 list_remove(&sink->entry);
307 heap_free(sink);
308 LeaveCriticalSection(&clock->cs);
309 return S_OK;
313 LeaveCriticalSection(&clock->cs);
315 return S_FALSE;
318 static const IReferenceClockVtbl SystemClock_vtbl =
320 SystemClockImpl_QueryInterface,
321 SystemClockImpl_AddRef,
322 SystemClockImpl_Release,
323 SystemClockImpl_GetTime,
324 SystemClockImpl_AdviseTime,
325 SystemClockImpl_AdvisePeriodic,
326 SystemClockImpl_Unadvise
329 HRESULT system_clock_create(IUnknown *outer, IUnknown **out)
331 struct system_clock *object;
333 TRACE("outer %p, out %p.\n", outer, out);
335 if (!(object = heap_alloc_zero(sizeof(*object))))
337 *out = NULL;
338 return E_OUTOFMEMORY;
341 object->IReferenceClock_iface.lpVtbl = &SystemClock_vtbl;
342 object->IUnknown_inner.lpVtbl = &system_clock_inner_vtbl;
343 object->outer_unk = outer ? outer : &object->IUnknown_inner;
344 object->refcount = 1;
345 list_init(&object->sinks);
346 InitializeCriticalSection(&object->cs);
347 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SystemClockImpl.cs");
348 QueryPerformanceFrequency(&object->frequency);
350 TRACE("Created system clock %p.\n", object);
351 *out = &object->IUnknown_inner;
353 return S_OK;