Home | History | Annotate | Download | only in ports
      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