|
1 /* |
|
2 * Copyright 2012 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #include "SkTypes.h" |
|
9 |
|
10 #include "SkThreadUtils.h" |
|
11 #include "SkThreadUtils_pthread.h" |
|
12 |
|
13 #include <pthread.h> |
|
14 #include <signal.h> |
|
15 |
|
16 PThreadEvent::PThreadEvent() : fConditionFlag(false) { |
|
17 pthread_cond_init(&fCondition, NULL); |
|
18 pthread_mutex_init(&fConditionMutex, NULL); |
|
19 } |
|
20 PThreadEvent::~PThreadEvent() { |
|
21 pthread_mutex_destroy(&fConditionMutex); |
|
22 pthread_cond_destroy(&fCondition); |
|
23 } |
|
24 void PThreadEvent::trigger() { |
|
25 pthread_mutex_lock(&fConditionMutex); |
|
26 fConditionFlag = true; |
|
27 pthread_cond_signal(&fCondition); |
|
28 pthread_mutex_unlock(&fConditionMutex); |
|
29 } |
|
30 void PThreadEvent::wait() { |
|
31 pthread_mutex_lock(&fConditionMutex); |
|
32 while (!fConditionFlag) { |
|
33 pthread_cond_wait(&fCondition, &fConditionMutex); |
|
34 } |
|
35 pthread_mutex_unlock(&fConditionMutex); |
|
36 } |
|
37 bool PThreadEvent::isTriggered() { |
|
38 bool currentFlag; |
|
39 pthread_mutex_lock(&fConditionMutex); |
|
40 currentFlag = fConditionFlag; |
|
41 pthread_mutex_unlock(&fConditionMutex); |
|
42 return currentFlag; |
|
43 } |
|
44 |
|
45 SkThread_PThreadData::SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data) |
|
46 : fPThread() |
|
47 , fValidPThread(false) |
|
48 , fParam(data) |
|
49 , fEntryPoint(entryPoint) |
|
50 { |
|
51 pthread_attr_init(&fAttr); |
|
52 pthread_attr_setdetachstate(&fAttr, PTHREAD_CREATE_JOINABLE); |
|
53 } |
|
54 |
|
55 SkThread_PThreadData::~SkThread_PThreadData() { |
|
56 pthread_attr_destroy(&fAttr); |
|
57 } |
|
58 |
|
59 static void* thread_start(void* arg) { |
|
60 SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(arg); |
|
61 // Wait for start signal |
|
62 pthreadData->fStarted.wait(); |
|
63 |
|
64 // Call entry point only if thread was not canceled before starting. |
|
65 if (!pthreadData->fCanceled.isTriggered()) { |
|
66 pthreadData->fEntryPoint(pthreadData->fParam); |
|
67 } |
|
68 return NULL; |
|
69 } |
|
70 |
|
71 SkThread::SkThread(entryPointProc entryPoint, void* data) { |
|
72 SkThread_PThreadData* pthreadData = new SkThread_PThreadData(entryPoint, data); |
|
73 fData = pthreadData; |
|
74 |
|
75 int ret = pthread_create(&(pthreadData->fPThread), |
|
76 &(pthreadData->fAttr), |
|
77 thread_start, |
|
78 pthreadData); |
|
79 |
|
80 pthreadData->fValidPThread = (0 == ret); |
|
81 } |
|
82 |
|
83 SkThread::~SkThread() { |
|
84 if (fData != NULL) { |
|
85 SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); |
|
86 // If created thread but start was never called, kill the thread. |
|
87 if (pthreadData->fValidPThread && !pthreadData->fStarted.isTriggered()) { |
|
88 pthreadData->fCanceled.trigger(); |
|
89 if (this->start()) { |
|
90 this->join(); |
|
91 } |
|
92 } |
|
93 delete pthreadData; |
|
94 } |
|
95 } |
|
96 |
|
97 bool SkThread::start() { |
|
98 SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); |
|
99 if (!pthreadData->fValidPThread) { |
|
100 return false; |
|
101 } |
|
102 |
|
103 if (pthreadData->fStarted.isTriggered()) { |
|
104 return false; |
|
105 } |
|
106 pthreadData->fStarted.trigger(); |
|
107 return true; |
|
108 } |
|
109 |
|
110 void SkThread::join() { |
|
111 SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); |
|
112 if (!pthreadData->fValidPThread || !pthreadData->fStarted.isTriggered()) { |
|
113 return; |
|
114 } |
|
115 |
|
116 pthread_join(pthreadData->fPThread, NULL); |
|
117 } |