ThreadPool.c revision d527933b750b107449263fff2c9d870edbfcc520
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); 29510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // closure is NULL when thread pool is being destroyed 30cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten if (NULL == pClosure) { 31d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten break; 32cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten } 33cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten // make a copy of parameters, then free the parameters 34cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten const Closure closure = *pClosure; 35510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten free(pClosure); 36cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten // extract parameters and call the right method depending on kind 37cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten ClosureKind kind = closure.mKind; 38cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten void *context1 = closure.mContext1; 39cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten void *context2 = closure.mContext2; 40cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten int parameter1 = closure.mParameter1; 41cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten switch (kind) { 4285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PPI: 43cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten { 4485133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi ClosureHandler_ppi handler_ppi = closure.mHandler.mHandler_ppi; 45cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten assert(NULL != handler_ppi); 46cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten (*handler_ppi)(context1, context2, parameter1); 47cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten } 48cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten break; 4985133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PPII: 50cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten { 5185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi ClosureHandler_ppii handler_ppii = closure.mHandler.mHandler_ppii; 52cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten assert(NULL != handler_ppii); 53cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten int parameter2 = closure.mParameter2; 54cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten (*handler_ppii)(context1, context2, parameter1, parameter2); 55cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten } 56cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten break; 5785133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PIIPP: 5885133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi { 5985133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi ClosureHandler_piipp handler_piipp = closure.mHandler.mHandler_piipp; 6085133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi assert(NULL != handler_piipp); 6185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi int parameter2 = closure.mParameter2; 6285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi void *context3 = closure.mContext3; 6385133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi (*handler_piipp)(context1, parameter1, parameter2, context2, context3); 6485133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi } 6585133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi break; 6685133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi default: 67cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten SL_LOGE("Unexpected callback kind %d", kind); 68cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten assert(false); 69cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten break; 70cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten } 71d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 72d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten return NULL; 73d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 74d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 75d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_NONE 0 76d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_MUTEX 1 77d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_CONDNOTFULL 2 78d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_CONDNOTEMPTY 4 79d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#define INITIALIZED_ALL 7 80d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 81d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic void ThreadPool_deinit_internal(ThreadPool *tp, unsigned initialized, unsigned nThreads); 82d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 83d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten// Initialize a ThreadPool 84d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten// maxClosures defaults to CLOSURE_TYPICAL if 0 85d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten// maxThreads defaults to THREAD_TYPICAL if 0 86d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 87d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn KastenSLresult ThreadPool_init(ThreadPool *tp, unsigned maxClosures, unsigned maxThreads) 88d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 89d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(NULL != tp); 90d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten memset(tp, 0, sizeof(ThreadPool)); 91d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mShutdown = SL_BOOLEAN_FALSE; 92510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten unsigned initialized = INITIALIZED_NONE; // which objects were successfully initialized 93510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten unsigned nThreads = 0; // number of threads successfully created 94510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten int err; 95d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten SLresult result; 96510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 97510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // initialize mutex and condition variables 98510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten err = pthread_mutex_init(&tp->mMutex, (const pthread_mutexattr_t *) NULL); 99510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = err_to_result(err); 100d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (SL_RESULT_SUCCESS != result) 101d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten goto fail; 102d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten initialized |= INITIALIZED_MUTEX; 103510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten err = pthread_cond_init(&tp->mCondNotFull, (const pthread_condattr_t *) NULL); 104510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = err_to_result(err); 105d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (SL_RESULT_SUCCESS != result) 106d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten goto fail; 107d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten initialized |= INITIALIZED_CONDNOTFULL; 108510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten err = pthread_cond_init(&tp->mCondNotEmpty, (const pthread_condattr_t *) NULL); 109510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = err_to_result(err); 110d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (SL_RESULT_SUCCESS != result) 111d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten goto fail; 112d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten initialized |= INITIALIZED_CONDNOTEMPTY; 113510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 114510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // use default values for parameters, if not specified explicitly 115d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mWaitingNotFull = 0; 116d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mWaitingNotEmpty = 0; 117d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (0 == maxClosures) 118d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten maxClosures = CLOSURE_TYPICAL; 119d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mMaxClosures = maxClosures; 120d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (0 == maxThreads) 121d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten maxThreads = THREAD_TYPICAL; 122d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mMaxThreads = maxThreads; 123510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 124510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // initialize circular buffer for closures 125d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (CLOSURE_TYPICAL >= maxClosures) { 126d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mClosureArray = tp->mClosureTypical; 127d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } else { 128d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mClosureArray = (Closure **) malloc((maxClosures + 1) * sizeof(Closure *)); 129d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (NULL == tp->mClosureArray) { 130d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten result = SL_RESULT_RESOURCE_ERROR; 131d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten goto fail; 132d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 133d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 134d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mClosureFront = tp->mClosureArray; 135d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mClosureRear = tp->mClosureArray; 136510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 137510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // initialize thread pool 138d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (THREAD_TYPICAL >= maxThreads) { 139d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mThreadArray = tp->mThreadTypical; 140d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } else { 141d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mThreadArray = (pthread_t *) malloc(maxThreads * sizeof(pthread_t)); 142d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (NULL == tp->mThreadArray) { 143d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten result = SL_RESULT_RESOURCE_ERROR; 144d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten goto fail; 145d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 146d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 147d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten unsigned i; 148d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten for (i = 0; i < maxThreads; ++i) { 149510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten int err = pthread_create(&tp->mThreadArray[i], (const pthread_attr_t *) NULL, 150510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten ThreadPool_start, tp); 151510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = err_to_result(err); 152d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (SL_RESULT_SUCCESS != result) 153d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten goto fail; 154d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ++nThreads; 155d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 156d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mInitialized = initialized; 157510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 158510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // done 159d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten return SL_RESULT_SUCCESS; 160510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 161510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // here on any kind of error 162d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenfail: 163d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ThreadPool_deinit_internal(tp, initialized, nThreads); 164d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten return result; 165d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 166d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 167d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic void ThreadPool_deinit_internal(ThreadPool *tp, unsigned initialized, unsigned nThreads) 168d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 1694597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten int ok; 1704597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten 171d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(NULL != tp); 172d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten // Destroy all threads 173d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (0 < nThreads) { 174d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(INITIALIZED_ALL == initialized); 175d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_lock(&tp->mMutex); 176d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 177d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mShutdown = SL_BOOLEAN_TRUE; 178d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_broadcast(&tp->mCondNotEmpty); 179d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 180d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_broadcast(&tp->mCondNotFull); 181d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 182d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 183d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 184d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten unsigned i; 185d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten for (i = 0; i < nThreads; ++i) { 186d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_join(tp->mThreadArray[i], (void **) NULL); 187d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(ok == 0); 188d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 189510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 190510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // Empty out the circular buffer of closures 191d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_lock(&tp->mMutex); 192d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 193d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == tp->mWaitingNotEmpty); 194510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten Closure **oldFront = tp->mClosureFront; 195510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten while (oldFront != tp->mClosureRear) { 196510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten Closure **newFront = oldFront; 197510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten if (++newFront == &tp->mClosureArray[tp->mMaxClosures + 1]) 198510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten newFront = tp->mClosureArray; 199510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten Closure *pClosure = *oldFront; 200510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(NULL != pClosure); 201510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten *oldFront = NULL; 202510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten tp->mClosureFront = newFront; 203510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 204510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(0 == ok); 205510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten free(pClosure); 206510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten ok = pthread_mutex_lock(&tp->mMutex); 207510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(0 == ok); 208510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 209d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 210d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 211d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten // Note that we can't be sure when mWaitingNotFull will drop to zero 212d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 213510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 214510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // destroy the mutex and condition variables 2154597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten if (initialized & INITIALIZED_CONDNOTEMPTY) { 2164597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten ok = pthread_cond_destroy(&tp->mCondNotEmpty); 2174597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 2184597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten } 2194597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten if (initialized & INITIALIZED_CONDNOTFULL) { 2204597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten ok = pthread_cond_destroy(&tp->mCondNotFull); 2214597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 2224597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten } 2234597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten if (initialized & INITIALIZED_MUTEX) { 2244597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten ok = pthread_mutex_destroy(&tp->mMutex); 2254597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 2264597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten } 227d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mInitialized = INITIALIZED_NONE; 228510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 229510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // release the closure circular buffer 230d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (tp->mClosureTypical != tp->mClosureArray && NULL != tp->mClosureArray) { 231d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten free(tp->mClosureArray); 232d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mClosureArray = NULL; 233d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 234510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 235510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // release the thread pool 236d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (tp->mThreadTypical != tp->mThreadArray && NULL != tp->mThreadArray) { 237d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten free(tp->mThreadArray); 238d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mThreadArray = NULL; 239d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 240510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 241d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 242d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 243d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenvoid ThreadPool_deinit(ThreadPool *tp) 244d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 245d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ThreadPool_deinit_internal(tp, tp->mInitialized, tp->mMaxThreads); 246d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 247d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 248cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten// Enqueue a closure to be executed later by a worker thread. 249cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten// Note that this raw interface requires an explicit "kind" and full parameter list. 250cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten// There are convenience methods below that make this easier to use. 25185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel TriviSLresult ThreadPool_add(ThreadPool *tp, ClosureKind kind, ClosureHandler_generic handler, 25285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi void *context1, void *context2, void *context3, int parameter1, int parameter2) 253d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 254d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(NULL != tp); 255510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(NULL != handler); 256510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten Closure *closure = (Closure *) malloc(sizeof(Closure)); 257cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten if (NULL == closure) { 258510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten return SL_RESULT_RESOURCE_ERROR; 259cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten } 260cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mKind = kind; 26185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi switch(kind) { 26285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PPI: 26385133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi closure->mHandler.mHandler_ppi = (ClosureHandler_ppi)handler; 26485133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi break; 26585133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PPII: 26685133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi closure->mHandler.mHandler_ppii = (ClosureHandler_ppii)handler; 26785133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi break; 26885133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PIIPP: 26985133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi closure->mHandler.mHandler_piipp = (ClosureHandler_piipp)handler; 27085133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi break; 27185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi default: 27285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi SL_LOGE("ThreadPool_add() invalid closure kind %d", kind); 27385133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi assert(false); 27485133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi } 275cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mContext1 = context1; 276cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mContext2 = context2; 27785133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi closure->mContext3 = context3; 278cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mParameter1 = parameter1; 279cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mParameter2 = parameter2; 280d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten int ok; 281d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_lock(&tp->mMutex); 282d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 283510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // can't enqueue while thread pool shutting down 284510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten if (tp->mShutdown) { 285510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 286510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(0 == ok); 287510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten free(closure); 288510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten return SL_RESULT_PRECONDITIONS_VIOLATED; 289510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 290d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten for (;;) { 291d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure **oldRear = tp->mClosureRear; 292d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure **newRear = oldRear; 293d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (++newRear == &tp->mClosureArray[tp->mMaxClosures + 1]) 294d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten newRear = tp->mClosureArray; 295510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // if closure circular buffer is full, then wait for it to become non-full 296d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (newRear == tp->mClosureFront) { 297d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ++tp->mWaitingNotFull; 298d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_wait(&tp->mCondNotFull, &tp->mMutex); 299d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 300510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // can't enqueue while thread pool shutting down 301d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (tp->mShutdown) { 302d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 < tp->mWaitingNotFull); 303d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten --tp->mWaitingNotFull; 304d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 305d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 306510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten free(closure); 307510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten return SL_RESULT_PRECONDITIONS_VIOLATED; 308d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 309d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten continue; 310d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 311d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(NULL == *oldRear); 312d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *oldRear = closure; 313d4b099b83a686a7bb88f5e36c063f5efe623b56dGlenn Kasten tp->mClosureRear = newRear; 314510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // if a worker thread was waiting to dequeue, then suggest that it try again 315d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (0 < tp->mWaitingNotEmpty) { 316d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten --tp->mWaitingNotEmpty; 317d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_signal(&tp->mCondNotEmpty); 318d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 319d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 320d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten break; 321d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 322d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 323d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 324510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten return SL_RESULT_SUCCESS; 325d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 326d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 327510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread when it is ready to accept the next closure to execute 328d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn KastenClosure *ThreadPool_remove(ThreadPool *tp) 329d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 330d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure *pClosure; 331d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten int ok; 332d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_lock(&tp->mMutex); 333d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 334d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten for (;;) { 335d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten // fail if thread pool is shutting down 336d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten if (tp->mShutdown) { 337d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten pClosure = NULL; 338d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten break; 339d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten } 340d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure **oldFront = tp->mClosureFront; 341510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // if closure circular buffer is empty, then wait for it to become non-empty 342d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (oldFront == tp->mClosureRear) { 343d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ++tp->mWaitingNotEmpty; 344d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_wait(&tp->mCondNotEmpty, &tp->mMutex); 345d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 346510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // try again 347d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten continue; 348d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 349510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // dequeue the closure at front of circular buffer 350d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure **newFront = oldFront; 351d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten if (++newFront == &tp->mClosureArray[tp->mMaxClosures + 1]) { 352d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten newFront = tp->mClosureArray; 353d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten } 354d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten pClosure = *oldFront; 355510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(NULL != pClosure); 356510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten *oldFront = NULL; 357d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mClosureFront = newFront; 358510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // if a client thread was waiting to enqueue, then suggest that it try again 359d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (0 < tp->mWaitingNotFull) { 360d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten --tp->mWaitingNotFull; 361d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_signal(&tp->mCondNotFull); 362d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 363d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 364d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten break; 365d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 366d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 367d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 368d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten return pClosure; 369d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 370cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten 371cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten// Convenience methods for applications 372cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn KastenSLresult ThreadPool_add_ppi(ThreadPool *tp, ClosureHandler_ppi handler, 373cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten void *context1, void *context2, int parameter1) 374cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten{ 375cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten // function pointers are the same size so this is a safe cast 37685133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi return ThreadPool_add(tp, CLOSURE_KIND_PPI, (ClosureHandler_generic) handler, 37785133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi context1, context2, NULL, parameter1, 0); 378cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten} 379cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten 380cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn KastenSLresult ThreadPool_add_ppii(ThreadPool *tp, ClosureHandler_ppii handler, 381cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten void *context1, void *context2, int parameter1, int parameter2) 382cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten{ 38385133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi // function pointers are the same size so this is a safe cast 38485133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi return ThreadPool_add(tp, CLOSURE_KIND_PPII, (ClosureHandler_generic) handler, 38585133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi context1, context2, NULL, parameter1, parameter2); 38685133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi} 38785133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi 38885133c817f6f387cd7d072988a8818f18bb53702Jean-Michel TriviSLresult ThreadPool_add_piipp(ThreadPool *tp, ClosureHandler_piipp handler, 38985133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi void *cntxt1, int param1, int param2, void *cntxt2, void *cntxt3) 39085133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi{ 39185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi // function pointers are the same size so this is a safe cast 39285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi return ThreadPool_add(tp, CLOSURE_KIND_PIIPP, (ClosureHandler_generic) handler, 39385133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi cntxt1, cntxt2, cntxt3, param1, param2); 394cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten} 395