1eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *
3eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * Redistribution and use in source and binary forms, with or without
4eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * modification, are permitted provided that the following conditions are
5eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * met:
6eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *     * Redistributions of source code must retain the above copyright
7eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *       notice, this list of conditions and the following disclaimer.
8eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *     * Redistributions in binary form must reproduce the above
9eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *       copyright notice, this list of conditions and the following
10eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *       disclaimer in the documentation and/or other materials provided
11eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *       with the distribution.
12eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *     * Neither the name of The Linux Foundation, nor the names of its
13eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *       contributors may be used to endorse or promote products derived
14eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *       from this software without specific prior written permission.
15eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *
16eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh *
28eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh */
29eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#include <LocThread.h>
30eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#include <string.h>
31eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#include <pthread.h>
32eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#include <platform_lib_macros.h>
33eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
34eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhclass LocThreadDelegate {
35eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    LocRunnable* mRunnable;
36eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    bool mJoinable;
37eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    pthread_t mThandle;
38eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    pthread_mutex_t mMutex;
39eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    int mRefCount;
40eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    ~LocThreadDelegate();
41eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    LocThreadDelegate(LocThread::tCreate creator, const char* threadName,
42eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh                      LocRunnable* runnable, bool joinable);
43eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    void destroy();
44eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhpublic:
45eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    static LocThreadDelegate* create(LocThread::tCreate creator,
46eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            const char* threadName, LocRunnable* runnable, bool joinable);
47eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    void stop();
48eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // bye() is for the parent thread to go away. if joinable,
49eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // parent must stop the spawned thread, join, and then
50eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // destroy(); if detached, the parent can go straight
51eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // ahead to destroy()
52eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    inline void bye() { mJoinable ? stop() : destroy(); }
53eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    inline bool isRunning() { return (NULL != mRunnable); }
54eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    static void* threadMain(void* arg);
55eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh};
56eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
57eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// it is important to note that internal members must be
58eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// initialized to values as if pthread_create succeeds.
59eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// This is to avoid the race condition between the threads,
60eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// once the thread is created, some of these values will
61eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// be check in the spawned thread, and must set correctly
62eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// then and there.
63eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// However, upon pthread_create failure, the data members
64eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// must be set to  indicate failure, e.g. mRunnable, and
65eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// threashold approprietly for destroy(), e.g. mRefCount.
66eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain VongsouvanhLocThreadDelegate::LocThreadDelegate(LocThread::tCreate creator,
67eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        const char* threadName, LocRunnable* runnable, bool joinable) :
68eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    mRunnable(runnable), mJoinable(joinable), mThandle((pthread_t)NULL),
69eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    mMutex(PTHREAD_MUTEX_INITIALIZER), mRefCount(2) {
70eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
71eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // set up thread name, if nothing is passed in
72eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (!threadName) {
73eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        threadName = "LocThread";
74eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
75eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
76eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // create the thread here, then if successful
77eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // and a name is given, we set the thread name
78eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (creator) {
79eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mThandle = creator(threadName, threadMain, this);
80eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    } else if (pthread_create(&mThandle, NULL, threadMain, this)) {
81eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // pthread_create() failed
82eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mThandle = (pthread_t)NULL;
83eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
84eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
85eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (mThandle) {
86eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // set thread name
87eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        char lname[16];
88eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        int len = (sizeof(lname)>sizeof(threadName)) ?
89eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh          (sizeof(threadName) -1):(sizeof(lname) - 1);
90eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        memcpy(lname, threadName, len);
91eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        lname[len] = 0;
92eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // set the thread name here
93eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        pthread_setname_np(mThandle, lname);
94eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
95eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // detach, if not joinable
96eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        if (!joinable) {
97eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            pthread_detach(mThandle);
98eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        }
99eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    } else {
100eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // must set these values upon failure
101eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mRunnable = NULL;
102eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mJoinable = false;
103eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mRefCount = 1;
104eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
105eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
106eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
107eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhinline
108eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain VongsouvanhLocThreadDelegate::~LocThreadDelegate() {
109eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // at this point nothing should need done any more
110eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
111eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
112eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// factory method so that we could return NULL upon failure
113eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain VongsouvanhLocThreadDelegate* LocThreadDelegate::create(LocThread::tCreate creator,
114eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        const char* threadName, LocRunnable* runnable, bool joinable) {
115eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    LocThreadDelegate* thread = NULL;
116eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (runnable) {
117eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        thread = new LocThreadDelegate(creator, threadName, runnable, joinable);
118eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        if (thread && !thread->isRunning()) {
119eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            thread->destroy();
120eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            thread = NULL;
121eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        }
122eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
123eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
124eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    return thread;
125eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
126eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
127eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// The order is importang
128eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// NULLing mRunnalbe stops the while loop in threadMain()
129eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// join() if mJoinble must come before destroy() call, as
130eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// the obj must remain alive at this time so that mThandle
131eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// remains valud.
132eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhvoid LocThreadDelegate::stop() {
133eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // mRunnable and mJoinable are reset on different triggers.
134eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // mRunnable may get nulled on the spawned thread's way out;
135eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    //           or here.
136eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // mJouinable (if ever been true) gets falsed when client
137eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    //            thread triggers stop, with either a stop()
138eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    //            call or the client releases thread obj handle.
139eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (mRunnable) {
140eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mRunnable = NULL;
141eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
142eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (mJoinable) {
143eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mJoinable = false;
144eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        pthread_join(mThandle, NULL);
145eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
146eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // call destroy() to possibly delete the obj
147eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    destroy();
148eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
149eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
150eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// method for clients to call to release the obj
151eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// when it is a detached thread, the client thread
152eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// and the spawned thread can both try to destroy()
153eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// asynchronously. And we delete this obj when
154eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// mRefCount becomes 0.
155eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhvoid LocThreadDelegate::destroy() {
156eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // else case shouldn't happen, unless there is a
157eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // leaking obj. But only our code here has such
158eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // obj, so if we test our code well, else case
159eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    // will never happen
160eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (mRefCount > 0) {
161eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // we need a flag on the stack
162eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        bool callDelete = false;
163eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
164eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // critical section between threads
165eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        pthread_mutex_lock(&mMutex);
166eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // last destroy() call
167eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        callDelete = (1 == mRefCount--);
168eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        pthread_mutex_unlock(&mMutex);
169eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
170eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // upon last destroy() call we delete this obj
171eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        if (callDelete) {
172eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            delete this;
173eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        }
174eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
175eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
176eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
177eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhvoid* LocThreadDelegate::threadMain(void* arg) {
178eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    LocThreadDelegate* locThread = (LocThreadDelegate*)(arg);
179eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
180eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (locThread) {
181eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        LocRunnable* runnable = locThread->mRunnable;
182eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
183eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        if (runnable) {
184eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            if (locThread->isRunning()) {
185eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh                runnable->prerun();
186eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            }
187eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
188eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            while (locThread->isRunning() && runnable->run());
189eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
190eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            if (locThread->isRunning()) {
191eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh                runnable->postrun();
192eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            }
193eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
194eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            // at this time, locThread->mRunnable may or may not be NULL
195eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            // NULL it just to be safe and clean, as we want the field
196eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            // in the released memory slot to be NULL.
197eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            locThread->mRunnable = NULL;
198eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh            delete runnable;
199eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        }
200eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        locThread->destroy();
201eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
202eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
203eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    return NULL;
204eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
205eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
206eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain VongsouvanhLocThread::~LocThread() {
207eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (mThread) {
208eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mThread->bye();
209eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mThread = NULL;
210eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
211eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
212eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
213eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhbool LocThread::start(tCreate creator, const char* threadName, LocRunnable* runnable, bool joinable) {
214eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    bool success = false;
215eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (!mThread) {
216eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mThread = LocThreadDelegate::create(creator, threadName, runnable, joinable);
217eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        // true only if thread is created successfully
218eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        success = (NULL != mThread);
219eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
220eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    return success;
221eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
222eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
223eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhvoid LocThread::stop() {
224eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    if (mThread) {
225eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mThread->stop();
226eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        mThread = NULL;
227eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
228eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
229eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
230eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#ifdef __LOC_DEBUG__
231eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
232eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#include <stdio.h>
233eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#include <stdlib.h>
234eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#include <unistd.h>
235eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
236eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhclass LocRunnableTest1 : public LocRunnable {
237eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    int mID;
238eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhpublic:
239eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    LocRunnableTest1(int id) : LocRunnable(), mID(id) {}
240eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    virtual bool run() {
241eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        printf("LocRunnableTest1: %d\n", mID++);
242eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        sleep(1);
243eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh        return true;
244eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    }
245eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh};
246eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
247eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// on linux command line:
248eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// 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
249eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// test detached thread: valgrind ./a.out 0
250eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh// test joinable thread: valgrind ./a.out 1
251eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanhint main(int argc, char** argv) {
252eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    LocRunnableTest1 test(10);
253eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
254eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    LocThread thread;
255eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    thread.start("LocThreadTest", test, atoi(argv[1]));
256eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
257eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    sleep(10);
258eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
259eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    thread.stop();
260eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
261eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    sleep(5);
262eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
263eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh    return 0;
264eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh}
265eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh
266eee4b7537bec1ef4198a5c0c9cfb8ba232ad60cbAlain Vongsouvanh#endif
267