1 /* libs/graphics/ports/SkOSEvent_android.cpp 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include "SkEvent.h" 19 #include "utils/threads.h" 20 #include <stdio.h> 21 22 using namespace android; 23 24 Mutex gEventQMutex; 25 Condition gEventQCondition; 26 27 void SkEvent::SignalNonEmptyQueue() 28 { 29 gEventQCondition.broadcast(); 30 } 31 32 /////////////////////////////////////////////////////////////////// 33 34 #ifdef FMS_ARCH_ANDROID_ARM 35 36 // don't have pthreads.h, and therefore no timedwait(), so we punt for the demo 37 38 void SkEvent::SignalQueueTimer(SkMSec delay) 39 { 40 } 41 42 void SkEvent_start_timer_thread() 43 { 44 } 45 46 void SkEvent_stop_timer_thread() 47 { 48 } 49 50 #else 51 52 #include <pthread.h> 53 #include <errno.h> 54 55 static pthread_t gTimerThread; 56 static pthread_mutex_t gTimerMutex; 57 static pthread_cond_t gTimerCond; 58 static timespec gTimeSpec; 59 60 static void* timer_event_thread_proc(void*) 61 { 62 for (;;) 63 { 64 int status; 65 66 pthread_mutex_lock(&gTimerMutex); 67 68 timespec spec = gTimeSpec; 69 // mark our global to be zero 70 // so we don't call timedwait again on a stale value 71 gTimeSpec.tv_sec = 0; 72 gTimeSpec.tv_nsec = 0; 73 74 if (spec.tv_sec == 0 && spec.tv_nsec == 0) 75 status = pthread_cond_wait(&gTimerCond, &gTimerMutex); 76 else 77 status = pthread_cond_timedwait(&gTimerCond, &gTimerMutex, &spec); 78 79 if (status == 0) // someone signaled us with a new time 80 { 81 pthread_mutex_unlock(&gTimerMutex); 82 } 83 else 84 { 85 SkASSERT(status == ETIMEDOUT); // no need to unlock the mutex (its unlocked) 86 // this is the payoff. Signal the event queue to wake up 87 // and also check the delay-queue 88 gEventQCondition.broadcast(); 89 } 90 } 91 return 0; 92 } 93 94 #define kThousand (1000) 95 #define kMillion (kThousand * kThousand) 96 #define kBillion (kThousand * kThousand * kThousand) 97 98 void SkEvent::SignalQueueTimer(SkMSec delay) 99 { 100 pthread_mutex_lock(&gTimerMutex); 101 102 if (delay) 103 { 104 struct timeval tv; 105 gettimeofday(&tv, NULL); 106 107 // normalize tv 108 if (tv.tv_usec >= kMillion) 109 { 110 tv.tv_sec += tv.tv_usec / kMillion; 111 tv.tv_usec %= kMillion; 112 } 113 114 // add tv + delay, scale each up to land on nanoseconds 115 gTimeSpec.tv_nsec = (tv.tv_usec + (delay % kThousand) * kThousand) * kThousand; 116 gTimeSpec.tv_sec = (tv.tv_sec + (delay / kThousand) * kThousand) * kThousand; 117 118 // check for overflow in nsec 119 if ((unsigned long)gTimeSpec.tv_nsec >= kBillion) 120 { 121 gTimeSpec.tv_nsec -= kBillion; 122 gTimeSpec.tv_sec += 1; 123 SkASSERT((unsigned long)gTimeSpec.tv_nsec < kBillion); 124 } 125 126 // printf("SignalQueueTimer(%d) timespec(%d %d)\n", delay, gTimeSpec.tv_sec, gTimeSpec.tv_nsec); 127 } 128 else // cancel the timer 129 { 130 gTimeSpec.tv_nsec = 0; 131 gTimeSpec.tv_sec = 0; 132 } 133 134 pthread_mutex_unlock(&gTimerMutex); 135 pthread_cond_signal(&gTimerCond); 136 } 137 138 void SkEvent_start_timer_thread() 139 { 140 int status; 141 pthread_attr_t attr; 142 143 status = pthread_attr_init(&attr); 144 SkASSERT(status == 0); 145 status = pthread_create(&gTimerThread, &attr, timer_event_thread_proc, 0); 146 SkASSERT(status == 0); 147 } 148 149 void SkEvent_stop_timer_thread() 150 { 151 int status = pthread_cancel(gTimerThread); 152 SkASSERT(status == 0); 153 } 154 155 #endif 156