/* libs/graphics/ports/SkOSEvent_android.cpp ** ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include "SkEvent.h" #include "utils/threads.h" #include <stdio.h> using namespace android; Mutex gEventQMutex; Condition gEventQCondition; void SkEvent::SignalNonEmptyQueue() { gEventQCondition.broadcast(); } /////////////////////////////////////////////////////////////////// #ifdef FMS_ARCH_ANDROID_ARM // don't have pthreads.h, and therefore no timedwait(), so we punt for the demo void SkEvent::SignalQueueTimer(SkMSec delay) { } void SkEvent_start_timer_thread() { } void SkEvent_stop_timer_thread() { } #else #include <pthread.h> #include <errno.h> static pthread_t gTimerThread; static pthread_mutex_t gTimerMutex; static pthread_cond_t gTimerCond; static timespec gTimeSpec; static void* timer_event_thread_proc(void*) { for (;;) { int status; pthread_mutex_lock(&gTimerMutex); timespec spec = gTimeSpec; // mark our global to be zero // so we don't call timedwait again on a stale value gTimeSpec.tv_sec = 0; gTimeSpec.tv_nsec = 0; if (spec.tv_sec == 0 && spec.tv_nsec == 0) status = pthread_cond_wait(&gTimerCond, &gTimerMutex); else status = pthread_cond_timedwait(&gTimerCond, &gTimerMutex, &spec); if (status == 0) // someone signaled us with a new time { pthread_mutex_unlock(&gTimerMutex); } else { SkASSERT(status == ETIMEDOUT); // no need to unlock the mutex (its unlocked) // this is the payoff. Signal the event queue to wake up // and also check the delay-queue gEventQCondition.broadcast(); } } return 0; } #define kThousand (1000) #define kMillion (kThousand * kThousand) #define kBillion (kThousand * kThousand * kThousand) void SkEvent::SignalQueueTimer(SkMSec delay) { pthread_mutex_lock(&gTimerMutex); if (delay) { struct timeval tv; gettimeofday(&tv, NULL); // normalize tv if (tv.tv_usec >= kMillion) { tv.tv_sec += tv.tv_usec / kMillion; tv.tv_usec %= kMillion; } // add tv + delay, scale each up to land on nanoseconds gTimeSpec.tv_nsec = (tv.tv_usec + (delay % kThousand) * kThousand) * kThousand; gTimeSpec.tv_sec = (tv.tv_sec + (delay / kThousand) * kThousand) * kThousand; // check for overflow in nsec if ((unsigned long)gTimeSpec.tv_nsec >= kBillion) { gTimeSpec.tv_nsec -= kBillion; gTimeSpec.tv_sec += 1; SkASSERT((unsigned long)gTimeSpec.tv_nsec < kBillion); } // printf("SignalQueueTimer(%d) timespec(%d %d)\n", delay, gTimeSpec.tv_sec, gTimeSpec.tv_nsec); } else // cancel the timer { gTimeSpec.tv_nsec = 0; gTimeSpec.tv_sec = 0; } pthread_mutex_unlock(&gTimerMutex); pthread_cond_signal(&gTimerCond); } void SkEvent_start_timer_thread() { int status; pthread_attr_t attr; status = pthread_attr_init(&attr); SkASSERT(status == 0); status = pthread_create(&gTimerThread, &attr, timer_event_thread_proc, 0); SkASSERT(status == 0); } void SkEvent_stop_timer_thread() { int status = pthread_cancel(gTimerThread); SkASSERT(status == 0); } #endif