aboutsummaryrefslogtreecommitdiffstats
path: root/libsgl/ports/SkOSEvent_android.cpp
blob: 59d6191684b4359888081c77111db9877fa5a3a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* 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