13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Utility Library
33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * ----------------------------
43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project
63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License");
83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License.
93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at
103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *      http://www.apache.org/licenses/LICENSE-2.0
123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software
143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS,
153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and
173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License.
183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*!
203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file
213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Periodic timer.
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deTimer.h"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMemory.h"
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deThread.h"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#if (DE_OS == DE_OS_WIN32)
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#define VC_EXTRALEAN
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#define WIN32_LEAN_AND_MEAN
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <windows.h>
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct deTimer_s
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimerCallback		callback;
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*				callbackArg;
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	HANDLE				timer;
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void CALLBACK timerCallback (PVOID lpParameter, BOOLEAN timerOrWaitFired)
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deTimer* timer = (const deTimer*)lpParameter;
453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_UNREF(timerOrWaitFired);
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->callback(timer->callbackArg);
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
503c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeTimer* deTimer_create (deTimerCallback callback, void* arg)
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimer* timer = (deTimer*)deCalloc(sizeof(deTimer));
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!timer)
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_NULL;
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->callback		= callback;
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->callbackArg	= arg;
593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->timer		= 0;
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return timer;
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
643c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid deTimer_destroy (deTimer* timer)
653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(timer);
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (deTimer_isActive(timer))
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deTimer_disable(timer);
703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deFree(timer);
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
743c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_isActive (const deTimer* timer)
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return timer->timer != 0;
773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
793c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_scheduleSingle (deTimer* timer, int milliseconds)
803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	BOOL ret;
823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(timer && milliseconds > 0);
843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (deTimer_isActive(timer))
863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ret = CreateTimerQueueTimer(&timer->timer, NULL, timerCallback, timer, (DWORD)milliseconds, 0, WT_EXECUTEDEFAULT);
893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!ret)
913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(!timer->timer);
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return DE_TRUE;
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
993c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_scheduleInterval (deTimer* timer, int milliseconds)
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	BOOL ret;
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(timer && milliseconds > 0);
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (deTimer_isActive(timer))
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ret = CreateTimerQueueTimer(&timer->timer, NULL, timerCallback, timer, (DWORD)milliseconds, (DWORD)milliseconds, WT_EXECUTEDEFAULT);
1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!ret)
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(!timer->timer);
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return DE_TRUE;
1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid deTimer_disable (deTimer* timer)
1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer->timer)
1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	maxTries	= 100;
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		HANDLE		waitEvent	= CreateEvent(NULL, FALSE, FALSE, NULL);
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int			tryNdx		= 0;
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(waitEvent);
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (tryNdx = 0; tryNdx < maxTries; tryNdx++)
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			BOOL success = DeleteTimerQueueTimer(NULL, timer->timer, waitEvent);
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (success)
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				/* Wait for all callbacks to complete. */
1345f78b1323b6ef28d8b9cdce6fefcbbb61a0477a9Pyry Haulos				DWORD res = WaitForSingleObject(waitEvent, INFINITE);
1355f78b1323b6ef28d8b9cdce6fefcbbb61a0477a9Pyry Haulos				DE_ASSERT(res == WAIT_OBJECT_0);
1365f78b1323b6ef28d8b9cdce6fefcbbb61a0477a9Pyry Haulos				DE_UNREF(res);
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				break;
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			else
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				DWORD err = GetLastError();
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (err == ERROR_IO_PENDING)
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					break; /* \todo [2013-03-21 pyry] Does this mean that callback is still in progress? */
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				deYield();
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(tryNdx < maxTries);
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CloseHandle(waitEvent);
1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		timer->timer = 0;
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
155c5cf5cb5dd01910d08bb5e600fea7179d89f9a68Pyry Haulos#elif (DE_OS == DE_OS_UNIX || DE_OS == DE_OS_ANDROID || DE_OS == DE_OS_SYMBIAN || DE_OS == DE_OS_QNX)
1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <signal.h>
1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <time.h>
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct deTimer_s
1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimerCallback		callback;
1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*				callbackArg;
1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer_t				timer;
1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deBool				isActive;
1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void timerCallback (union sigval val)
1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deTimer* timer = (const deTimer*)val.sival_ptr;
1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->callback(timer->callbackArg);
1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1763c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeTimer* deTimer_create (deTimerCallback callback, void* arg)
1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimer*		timer = (deTimer*)deCalloc(sizeof(deTimer));
1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	struct sigevent	sevp;
1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!timer)
1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_NULL;
1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deMemset(&sevp, 0, sizeof(sevp));
1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	sevp.sigev_notify			= SIGEV_THREAD;
1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	sevp.sigev_value.sival_ptr	= timer;
1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	sevp.sigev_notify_function	= timerCallback;
1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer_create(CLOCK_REALTIME, &sevp, &timer->timer) != 0)
1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deFree(timer);
1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_NULL;
1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->callback		= callback;
1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->callbackArg	= arg;
1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->isActive		= DE_FALSE;
1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return timer;
2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid deTimer_destroy (deTimer* timer)
2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(timer);
2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer_delete(timer->timer);
2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deFree(timer);
2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2103c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_isActive (const deTimer* timer)
2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return timer->isActive;
2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2153c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_scheduleSingle (deTimer* timer, int milliseconds)
2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	struct itimerspec tspec;
2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(timer && milliseconds > 0);
2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer->isActive)
2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_value.tv_sec		= milliseconds / 1000;
2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_value.tv_nsec		= (milliseconds % 1000) * 1000;
2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_interval.tv_sec	= 0;
2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_interval.tv_nsec	= 0;
2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer_settime(timer->timer, 0, &tspec, DE_NULL) != 0)
2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->isActive = DE_TRUE;
2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return DE_TRUE;
2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2363c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_scheduleInterval (deTimer* timer, int milliseconds)
2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	struct itimerspec tspec;
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(timer && milliseconds > 0);
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer->isActive)
2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_value.tv_sec		= milliseconds / 1000;
2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_value.tv_nsec		= (milliseconds % 1000) * 1000;
2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_interval.tv_sec	= tspec.it_value.tv_sec;
2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_interval.tv_nsec	= tspec.it_value.tv_nsec;
2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer_settime(timer->timer, 0, &tspec, DE_NULL) != 0)
2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->isActive = DE_TRUE;
2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return DE_TRUE;
2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid deTimer_disable (deTimer* timer)
2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	struct itimerspec tspec;
2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(timer);
2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_value.tv_sec		= 0;
2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_value.tv_nsec		= 0;
2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_interval.tv_sec	= 0;
2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tspec.it_interval.tv_nsec	= 0;
2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer_settime(timer->timer, 0, &tspec, DE_NULL);
2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	/* \todo [2012-07-10 pyry] How to wait until all pending callbacks have finished? */
2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->isActive = DE_FALSE;
2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#else
2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/* Generic thread-based implementation for OSes that lack proper timers. */
2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deThread.h"
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMutex.h"
2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deClock.h"
2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytypedef enum TimerState_e
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TIMERSTATE_INTERVAL = 0,	/*!< Active interval timer.		*/
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TIMERSTATE_SINGLE,			/*!< Single callback timer.		*/
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TIMERSTATE_DISABLED,		/*!< Disabled timer.			*/
2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TIMERSTATE_LAST
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} TimerState;
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytypedef struct deTimerThread_s
2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimerCallback		callback;		/*!< Callback function.		*/
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*				callbackArg;	/*!< User pointer.			*/
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deThread			thread;			/*!< Thread.				*/
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int					interval;		/*!< Timer interval.		*/
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deMutex				lock;			/*!< State lock.			*/
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	volatile TimerState	state;			/*!< Timer state.			*/
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} deTimerThread;
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct deTimer_s
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimerCallback		callback;		/*!< Callback function.		*/
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void*				callbackArg;	/*!< User pointer.			*/
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimerThread*		curThread;		/*!< Current timer thread.	*/
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void timerThread (void* arg)
3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimerThread*	thread			= (deTimerThread*)arg;
3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int				numCallbacks	= 0;
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deBool			destroy			= DE_TRUE;
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deInt64			lastCallback	= (deInt64)deGetMicroseconds();
3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (;;)
3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int sleepTime = 0;
3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_lock(thread->lock);
3233fdee359c9eee4d6c1d823b23f7f64631b5945f8Jarkko Pöyry
3243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (thread->state == TIMERSTATE_SINGLE && numCallbacks > 0)
3253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			destroy = DE_FALSE; /* Will be destroyed by deTimer_disable(). */
3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			thread->state = TIMERSTATE_DISABLED;
3283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (thread->state == TIMERSTATE_DISABLED)
3313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			break;
3323fdee359c9eee4d6c1d823b23f7f64631b5945f8Jarkko Pöyry
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_unlock(thread->lock);
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		sleepTime = thread->interval - (int)(((deInt64)deGetMicroseconds()-lastCallback)/1000);
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (sleepTime > 0)
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			deSleep(sleepTime);
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		lastCallback = (deInt64)deGetMicroseconds();
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		thread->callback(thread->callbackArg);
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		numCallbacks += 1;
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	/* State lock is held when loop is exited. */
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deMutex_unlock(thread->lock);
3463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (destroy)
3483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		/* Destroy thread except thread->thread. */
3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_destroy(thread->lock);
3513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deFree(thread);
3523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic deTimerThread* deTimerThread_create (deTimerCallback callback, void* arg, int interval, TimerState state)
3563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimerThread* thread = (deTimerThread*)deCalloc(sizeof(deTimerThread));
3583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(state == TIMERSTATE_INTERVAL || state == TIMERSTATE_SINGLE);
3603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!thread)
3623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_NULL;
3633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	thread->callback	= callback;
3653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	thread->callbackArg	= arg;
3663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	thread->interval	= interval;
3673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	thread->lock		= deMutex_create(DE_NULL);
3683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	thread->state		= state;
3693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	thread->thread		= deThread_create(timerThread, thread, DE_NULL);
3713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!thread->thread)
3723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_destroy(thread->lock);
3743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deFree(thread);
3753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_NULL;
3763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return thread;
3793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3813c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeTimer* deTimer_create (deTimerCallback callback, void* arg)
3823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deTimer* timer = (deTimer*)deCalloc(sizeof(deTimer));
3843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!timer)
3863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_NULL;
3873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->callback		= callback;
3893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->callbackArg	= arg;
3903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return timer;
3923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3943c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid deTimer_destroy (deTimer* timer)
3953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer->curThread)
3973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deTimer_disable(timer);
3983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deFree(timer);
3993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4013c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_isActive (const deTimer* timer)
4023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer->curThread)
4043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deBool isActive = DE_FALSE;
4063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_lock(timer->curThread->lock);
4083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		isActive = timer->curThread->state != TIMERSTATE_LAST;
4093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_unlock(timer->curThread->lock);
4103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return isActive;
4123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
4143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return DE_FALSE;
4153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4173c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_scheduleSingle (deTimer* timer, int milliseconds)
4183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer->curThread)
4203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deTimer_disable(timer);
4213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!timer->curThread);
4233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->curThread = deTimerThread_create(timer->callback, timer->callbackArg, milliseconds, TIMERSTATE_SINGLE);
4243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return timer->curThread != DE_NULL;
4263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4283c827367444ee418f129b2c238299f49d3264554Jarkko PoyrydeBool deTimer_scheduleInterval (deTimer* timer, int milliseconds)
4293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer->curThread)
4313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deTimer_disable(timer);
4323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!timer->curThread);
4343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->curThread = deTimerThread_create(timer->callback, timer->callbackArg, milliseconds, TIMERSTATE_INTERVAL);
4353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return timer->curThread != DE_NULL;
4373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4393c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid deTimer_disable (deTimer* timer)
4403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!timer->curThread)
4423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return;
4433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deMutex_lock(timer->curThread->lock);
4453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (timer->curThread->state != TIMERSTATE_DISABLED)
4473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		/* Just set state to disabled and destroy thread handle. */
4493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		/* \note Assumes that deThread_destroy() can be called while thread is still running
4503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		 *       and it will not terminate the thread.
4513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		 */
4523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		timer->curThread->state = TIMERSTATE_DISABLED;
4533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deThread_destroy(timer->curThread->thread);
4543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		timer->curThread->thread = 0;
4553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_unlock(timer->curThread->lock);
4563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		/* Thread will destroy timer->curThread. */
4583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
4603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		/* Single timer has expired - we must destroy whole thread structure. */
4623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_unlock(timer->curThread->lock);
4633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deThread_destroy(timer->curThread->thread);
4643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deMutex_destroy(timer->curThread->lock);
4653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deFree(timer->curThread);
4663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	timer->curThread = DE_NULL;
4693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#endif
472