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