ThreadPool.cpp revision d2a7f0d6883a6d3835642e7b282f05ed1c54fe63
1d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten/*
2d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
3d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *
4d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * you may not use this file except in compliance with the License.
6d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * You may obtain a copy of the License at
7d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *
8d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *
10d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * Unless required by applicable law or agreed to in writing, software
11d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * See the License for the specific language governing permissions and
14d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * limitations under the License.
15d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten */
16d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
17d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten/* ThreadPool */
18d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
19d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#include "sles_allinclusive.h"
20d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
21d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten// Entry point for each worker thread
22d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
23d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic void *ThreadPool_start(void *context)
24d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
25d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    ThreadPool *tp = (ThreadPool *) context;
26d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(NULL != tp);
27d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    for (;;) {
28d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        Closure *pClosure = ThreadPool_remove(tp);
29d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        // closure is NULL when engine is being destroyed
30d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (NULL == pClosure)
31d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            break;
32d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        void (*handler)(Closure *);
33d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        handler = pClosure->mHandler;
34d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(NULL != handler);
35d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        (*handler)(pClosure);
36d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
37d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    return NULL;
38d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
39d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
40d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_NONE         0
41d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_MUTEX        1
42d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_CONDNOTFULL  2
43d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_CONDNOTEMPTY 4
44d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_ALL          7
45d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
46d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic void ThreadPool_deinit_internal(ThreadPool *tp, unsigned initialized, unsigned nThreads);
47d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
48d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten// Initialize a ThreadPool
49d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten// maxClosures defaults to CLOSURE_TYPICAL if 0
50d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten// maxThreads defaults to THREAD_TYPICAL if 0
51d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
52d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn KastenSLresult ThreadPool_init(ThreadPool *tp, unsigned maxClosures, unsigned maxThreads)
53d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
54d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(NULL != tp);
55d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    memset(tp, 0, sizeof(ThreadPool));
56d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mShutdown = SL_BOOLEAN_FALSE;
57d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    unsigned initialized = INITIALIZED_NONE;
58d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    unsigned nThreads = 0;
59d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    SLresult result;
60d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    result = err_to_result(pthread_mutex_init(&tp->mMutex, (const pthread_mutexattr_t *) NULL));
61d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (SL_RESULT_SUCCESS != result)
62d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        goto fail;
63d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    initialized |= INITIALIZED_MUTEX;
64d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    result = err_to_result(pthread_cond_init(&tp->mCondNotFull, (const pthread_condattr_t *) NULL));
65d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (SL_RESULT_SUCCESS != result)
66d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        goto fail;
67d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    initialized |= INITIALIZED_CONDNOTFULL;
68d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    result = err_to_result(pthread_cond_init(&tp->mCondNotEmpty, (const pthread_condattr_t *) NULL));
69d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (SL_RESULT_SUCCESS != result)
70d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        goto fail;
71d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    initialized |= INITIALIZED_CONDNOTEMPTY;
72d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mWaitingNotFull = 0;
73d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mWaitingNotEmpty = 0;
74d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (0 == maxClosures)
75d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        maxClosures = CLOSURE_TYPICAL;
76d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mMaxClosures = maxClosures;
77d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (0 == maxThreads)
78d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        maxThreads = THREAD_TYPICAL;
79d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mMaxThreads = maxThreads;
80d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (CLOSURE_TYPICAL >= maxClosures) {
81d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        tp->mClosureArray = tp->mClosureTypical;
82d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    } else {
83d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        tp->mClosureArray = (Closure **) malloc((maxClosures + 1) * sizeof(Closure *));
84d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (NULL == tp->mClosureArray) {
85d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            result = SL_RESULT_RESOURCE_ERROR;
86d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            goto fail;
87d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
88d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
89d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mClosureFront = tp->mClosureArray;
90d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mClosureRear = tp->mClosureArray;
91d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (THREAD_TYPICAL >= maxThreads) {
92d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        tp->mThreadArray = tp->mThreadTypical;
93d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    } else {
94d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        tp->mThreadArray = (pthread_t *) malloc(maxThreads * sizeof(pthread_t));
95d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (NULL == tp->mThreadArray) {
96d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            result = SL_RESULT_RESOURCE_ERROR;
97d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            goto fail;
98d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
99d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
100d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    unsigned i;
101d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    for (i = 0; i < maxThreads; ++i) {
102d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        result = err_to_result(pthread_create(&tp->mThreadArray[i], (const pthread_attr_t *) NULL, ThreadPool_start, tp));
103d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (SL_RESULT_SUCCESS != result)
104d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            goto fail;
105d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        ++nThreads;
106d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
107d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mInitialized = initialized;
108d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    return SL_RESULT_SUCCESS;
109d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenfail:
110d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    ThreadPool_deinit_internal(tp, initialized, nThreads);
111d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    return result;
112d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
113d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
114d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic void ThreadPool_deinit_internal(ThreadPool *tp, unsigned initialized, unsigned nThreads)
115d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
116d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(NULL != tp);
117d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // FIXME Cancel all pending operations
118d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Destroy all threads
119d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (0 < nThreads) {
120d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        int ok;
121d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(INITIALIZED_ALL == initialized);
122d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        ok = pthread_mutex_lock(&tp->mMutex);
123d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(0 == ok);
124d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        tp->mShutdown = SL_BOOLEAN_TRUE;
125d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        ok = pthread_cond_broadcast(&tp->mCondNotEmpty);
126d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(0 == ok);
127d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        ok = pthread_cond_broadcast(&tp->mCondNotFull);
128d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(0 == ok);
129d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        ok = pthread_mutex_unlock(&tp->mMutex);
130d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(0 == ok);
131d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        unsigned i;
132d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        for (i = 0; i < nThreads; ++i) {
133d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            ok = pthread_join(tp->mThreadArray[i], (void **) NULL);
134d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            assert(ok == 0);
135d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
136d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        ok = pthread_mutex_lock(&tp->mMutex);
137d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(0 == ok);
138d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(0 == tp->mWaitingNotEmpty);
139d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        ok = pthread_mutex_unlock(&tp->mMutex);
140d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(0 == ok);
141d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        // Note that we can't be sure when mWaitingNotFull will drop to zero
142d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
143d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (initialized & INITIALIZED_CONDNOTEMPTY)
144d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        (void) pthread_cond_destroy(&tp->mCondNotEmpty);
145d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (initialized & INITIALIZED_CONDNOTFULL)
146d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        (void) pthread_cond_destroy(&tp->mCondNotFull);
147d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (initialized & INITIALIZED_MUTEX)
148d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        (void) pthread_mutex_destroy(&tp->mMutex);
149d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    tp->mInitialized = INITIALIZED_NONE;
150d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (tp->mClosureTypical != tp->mClosureArray && NULL != tp->mClosureArray) {
151d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        free(tp->mClosureArray);
152d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        tp->mClosureArray = NULL;
153d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
154d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (tp->mThreadTypical != tp->mThreadArray && NULL != tp->mThreadArray) {
155d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        free(tp->mThreadArray);
156d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        tp->mThreadArray = NULL;
157d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
158d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
159d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
160d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenvoid ThreadPool_deinit(ThreadPool *tp)
161d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
162d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    ThreadPool_deinit_internal(tp, tp->mInitialized, tp->mMaxThreads);
163d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
164d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
165d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenbool ThreadPool_add(ThreadPool *tp, Closure *closure)
166d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
167d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(NULL != tp);
168d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(NULL != closure);
169d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    int ok;
170d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    ok = pthread_mutex_lock(&tp->mMutex);
171d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(0 == ok);
172d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    for (;;) {
173d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        Closure **oldRear = tp->mClosureRear;
174d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        Closure **newRear = oldRear;
175d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (++newRear == &tp->mClosureArray[tp->mMaxClosures + 1])
176d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            newRear = tp->mClosureArray;
177d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (newRear == tp->mClosureFront) {
178d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            ++tp->mWaitingNotFull;
179d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            ok = pthread_cond_wait(&tp->mCondNotFull, &tp->mMutex);
180d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            assert(0 == ok);
181d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            if (tp->mShutdown) {
182d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                assert(0 < tp->mWaitingNotFull);
183d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                --tp->mWaitingNotFull;
184d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                ok = pthread_mutex_unlock(&tp->mMutex);
185d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                assert(0 == ok);
186d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                return false;
187d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            }
188d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            continue;
189d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
190d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(NULL == *oldRear);
191d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        *oldRear = closure;
192d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (0 < tp->mWaitingNotEmpty) {
193d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            --tp->mWaitingNotEmpty;
194d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            ok = pthread_cond_signal(&tp->mCondNotEmpty);
195d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            assert(0 == ok);
196d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
197d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        break;
198d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
199d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    ok = pthread_mutex_unlock(&tp->mMutex);
200d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(0 == ok);
201d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    return true;
202d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
203d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
204d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn KastenClosure *ThreadPool_remove(ThreadPool *tp)
205d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
206d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    Closure *pClosure;
207d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    int ok;
208d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    ok = pthread_mutex_lock(&tp->mMutex);
209d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(0 == ok);
210d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    for (;;) {
211d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        Closure **oldFront = tp->mClosureFront;
212d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (oldFront == tp->mClosureRear) {
213d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            ++tp->mWaitingNotEmpty;
214d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            ok = pthread_cond_wait(&tp->mCondNotEmpty, &tp->mMutex);
215d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            assert(0 == ok);
216d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            if (tp->mShutdown) {
217d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                assert(0 < tp->mWaitingNotEmpty);
218d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                --tp->mWaitingNotEmpty;
219d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                pClosure = NULL;
220d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                break;
221d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            }
222d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            continue;
223d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
224d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        Closure **newFront = oldFront;
225d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (++newFront == &tp->mClosureArray[tp->mMaxClosures + 1])
226d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            newFront = tp->mClosureArray;
227d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        pClosure = *oldFront;
228d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        tp->mClosureFront = newFront;
229d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (0 < tp->mWaitingNotFull) {
230d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            --tp->mWaitingNotFull;
231d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            ok = pthread_cond_signal(&tp->mCondNotFull);
232d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            assert(0 == ok);
233d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
234d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        break;
235d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
236d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    ok = pthread_mutex_unlock(&tp->mMutex);
237d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    assert(0 == ok);
238d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    return pClosure;
239d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
240