1129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *
3129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * Redistribution and use in source and binary forms, with or without
4129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * modification, are permitted provided that the following conditions are
5129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * met:
6129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *     * Redistributions of source code must retain the above copyright
7129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *       notice, this list of conditions and the following disclaimer.
8129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *     * Redistributions in binary form must reproduce the above
9129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *       copyright notice, this list of conditions and the following
10129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *       disclaimer in the documentation and/or other materials provided
11129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *       with the distribution.
12129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *     * Neither the name of The Linux Foundation, nor the names of its
13129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *       contributors may be used to endorse or promote products derived
14129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *       from this software without specific prior written permission.
15129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *
16129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel *
28129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel */
29129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <LocThread.h>
30129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <string.h>
31129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <pthread.h>
32129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <platform_lib_macros.h>
33129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
34129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelclass LocThreadDelegate {
35129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    LocRunnable* mRunnable;
36129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    bool mJoinable;
37129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    pthread_t mThandle;
38129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    pthread_mutex_t mMutex;
39129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    int mRefCount;
40129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    ~LocThreadDelegate();
41129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    LocThreadDelegate(LocThread::tCreate creator, const char* threadName,
42129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel                      LocRunnable* runnable, bool joinable);
43129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    void destroy();
44129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpublic:
45129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    static LocThreadDelegate* create(LocThread::tCreate creator,
46129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            const char* threadName, LocRunnable* runnable, bool joinable);
47129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    void stop();
48129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // bye() is for the parent thread to go away. if joinable,
49129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // parent must stop the spawned thread, join, and then
50129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // destroy(); if detached, the parent can go straight
51129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // ahead to destroy()
52129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    inline void bye() { mJoinable ? stop() : destroy(); }
53129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    inline bool isRunning() { return (NULL != mRunnable); }
54129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    static void* threadMain(void* arg);
55129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel};
56129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
57129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// it is important to note that internal members must be
58129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// initialized to values as if pthread_create succeeds.
59129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// This is to avoid the race condition between the threads,
60129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// once the thread is created, some of these values will
61129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// be check in the spawned thread, and must set correctly
62129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// then and there.
63129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// However, upon pthread_create failure, the data members
64129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// must be set to  indicate failure, e.g. mRunnable, and
65129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// threashold approprietly for destroy(), e.g. mRefCount.
66129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocThreadDelegate::LocThreadDelegate(LocThread::tCreate creator,
67129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        const char* threadName, LocRunnable* runnable, bool joinable) :
68129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    mRunnable(runnable), mJoinable(joinable), mThandle(NULL),
69129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    mMutex(PTHREAD_MUTEX_INITIALIZER), mRefCount(2) {
70129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
71129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // set up thread name, if nothing is passed in
72129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (!threadName) {
73129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        threadName = "LocThread";
74129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
75129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
76129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // create the thread here, then if successful
77129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // and a name is given, we set the thread name
78129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (creator) {
79129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mThandle = creator(threadName, threadMain, this);
80129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    } else if (pthread_create(&mThandle, NULL, threadMain, this)) {
81129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // pthread_create() failed
82129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mThandle = NULL;
83129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
84129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
85129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (mThandle) {
86129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // set thread name
87129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        char lname[16];
886f2a63d31df9024574b97a242c5e89e9252cb895Thierry Strudel        int len = (sizeof(lname)>sizeof(threadName)) ?
896f2a63d31df9024574b97a242c5e89e9252cb895Thierry Strudel          (sizeof(threadName) -1):(sizeof(lname) - 1);
906f2a63d31df9024574b97a242c5e89e9252cb895Thierry Strudel        memcpy(lname, threadName, len);
916f2a63d31df9024574b97a242c5e89e9252cb895Thierry Strudel        lname[len] = 0;
92129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // set the thread name here
93129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        pthread_setname_np(mThandle, lname);
94129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
95129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // detach, if not joinable
96129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        if (!joinable) {
97129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            pthread_detach(mThandle);
98129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        }
99129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    } else {
100129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // must set these values upon failure
101129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mRunnable = NULL;
102129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mJoinable = false;
103129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mRefCount = 1;
104129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
105129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
106129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
107129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelinline
108129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocThreadDelegate::~LocThreadDelegate() {
109129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // at this point nothing should need done any more
110129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
111129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
112129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// factory method so that we could return NULL upon failure
113129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocThreadDelegate* LocThreadDelegate::create(LocThread::tCreate creator,
114129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        const char* threadName, LocRunnable* runnable, bool joinable) {
115129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    LocThreadDelegate* thread = NULL;
116129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (runnable) {
117129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        thread = new LocThreadDelegate(creator, threadName, runnable, joinable);
118129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        if (thread && !thread->isRunning()) {
119129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            thread->destroy();
120129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            thread = NULL;
121129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        }
122129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
123129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
124129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    return thread;
125129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
126129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
127129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// The order is importang
128129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// NULLing mRunnalbe stops the while loop in threadMain()
129129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// join() if mJoinble must come before destroy() call, as
130129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// the obj must remain alive at this time so that mThandle
131129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// remains valud.
132129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocThreadDelegate::stop() {
133129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // mRunnable and mJoinable are reset on different triggers.
134129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // mRunnable may get nulled on the spawned thread's way out;
135129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    //           or here.
136129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // mJouinable (if ever been true) gets falsed when client
137129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    //            thread triggers stop, with either a stop()
138129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    //            call or the client releases thread obj handle.
139129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (mRunnable) {
140129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mRunnable = NULL;
141129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
142129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (mJoinable) {
143129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mJoinable = false;
144129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        pthread_join(mThandle, NULL);
145129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
146129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // call destroy() to possibly delete the obj
147129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    destroy();
148129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
149129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
150129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// method for clients to call to release the obj
151129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// when it is a detached thread, the client thread
152129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// and the spawned thread can both try to destroy()
153129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// asynchronously. And we delete this obj when
154129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// mRefCount becomes 0.
155129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocThreadDelegate::destroy() {
156129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // else case shouldn't happen, unless there is a
157129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // leaking obj. But only our code here has such
158129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // obj, so if we test our code well, else case
159129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    // will never happen
160129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (mRefCount > 0) {
161129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // we need a flag on the stack
162129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        bool callDelete = false;
163129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
164129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // critical section between threads
165129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        pthread_mutex_lock(&mMutex);
166129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // last destroy() call
167129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        callDelete = (1 == mRefCount--);
168129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        pthread_mutex_unlock(&mMutex);
169129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
170129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // upon last destroy() call we delete this obj
171129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        if (callDelete) {
172129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            delete this;
173129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        }
174129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
175129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
176129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
177129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid* LocThreadDelegate::threadMain(void* arg) {
178129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    LocThreadDelegate* locThread = (LocThreadDelegate*)(arg);
179129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
180129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (locThread) {
181129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        LocRunnable* runnable = locThread->mRunnable;
182129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
183129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        if (runnable) {
184129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            if (locThread->isRunning()) {
185129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel                runnable->prerun();
186129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            }
187129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
188129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            while (locThread->isRunning() && runnable->run());
189129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
190129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            if (locThread->isRunning()) {
191129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel                runnable->postrun();
192129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            }
193129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
194129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            // at this time, locThread->mRunnable may or may not be NULL
195129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            // NULL it just to be safe and clean, as we want the field
196129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            // in the released memory slot to be NULL.
197129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            locThread->mRunnable = NULL;
198129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel            delete runnable;
199129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        }
200129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        locThread->destroy();
201129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
202129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
203129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    return NULL;
204129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
205129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
206129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry StrudelLocThread::~LocThread() {
207129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (mThread) {
208129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mThread->bye();
209129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mThread = NULL;
210129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
211129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
212129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
213129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelbool LocThread::start(tCreate creator, const char* threadName, LocRunnable* runnable, bool joinable) {
214129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    bool success = false;
215129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (!mThread) {
216129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mThread = LocThreadDelegate::create(creator, threadName, runnable, joinable);
217129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        // true only if thread is created successfully
218129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        success = (NULL != mThread);
219129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
220129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    return success;
221129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
222129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
223129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelvoid LocThread::stop() {
224129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    if (mThread) {
225129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mThread->stop();
226129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        mThread = NULL;
227129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
228129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
229129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
230129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#ifdef __LOC_DEBUG__
231129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
232129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <stdio.h>
233129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <stdlib.h>
234129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#include <unistd.h>
235129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
236129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelclass LocRunnableTest1 : public LocRunnable {
237129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    int mID;
238129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelpublic:
239129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    LocRunnableTest1(int id) : LocRunnable(), mID(id) {}
240129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    virtual bool run() {
241129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        printf("LocRunnableTest1: %d\n", mID++);
242129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        sleep(1);
243129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel        return true;
244129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    }
245129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel};
246129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
247129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// on linux command line:
248129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// compile: g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -std=c++0x -I. -I../../../../vendor/qcom/proprietary/gps-internal/unit-tests/fakes_for_host -I../../../../system/core/include -lpthread LocThread.cpp
249129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// test detached thread: valgrind ./a.out 0
250129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel// test joinable thread: valgrind ./a.out 1
251129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudelint main(int argc, char** argv) {
252129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    LocRunnableTest1 test(10);
253129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
254129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    LocThread thread;
255129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    thread.start("LocThreadTest", test, atoi(argv[1]));
256129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
257129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    sleep(10);
258129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
259129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    thread.stop();
260129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
261129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    sleep(5);
262129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
263129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel    return 0;
264129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel}
265129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel
266129edaf7d0025e2828a8bee025f7b1bac7a68da6Thierry Strudel#endif
267