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); 193510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten Closure **oldFront = tp->mClosureFront; 194510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten while (oldFront != tp->mClosureRear) { 195510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten Closure **newFront = oldFront; 196510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten if (++newFront == &tp->mClosureArray[tp->mMaxClosures + 1]) 197510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten newFront = tp->mClosureArray; 198510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten Closure *pClosure = *oldFront; 199510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(NULL != pClosure); 200510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten *oldFront = NULL; 201510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten tp->mClosureFront = newFront; 202510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 203510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(0 == ok); 204510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten free(pClosure); 205510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten ok = pthread_mutex_lock(&tp->mMutex); 206510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(0 == ok); 207510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 208d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 209d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 210d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten // Note that we can't be sure when mWaitingNotFull will drop to zero 211d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 212510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 213510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // destroy the mutex and condition variables 2144597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten if (initialized & INITIALIZED_CONDNOTEMPTY) { 2154597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten ok = pthread_cond_destroy(&tp->mCondNotEmpty); 2164597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 2174597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten } 2184597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten if (initialized & INITIALIZED_CONDNOTFULL) { 2194597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten ok = pthread_cond_destroy(&tp->mCondNotFull); 2204597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 2214597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten } 2224597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten if (initialized & INITIALIZED_MUTEX) { 2234597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten ok = pthread_mutex_destroy(&tp->mMutex); 2244597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 2254597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten } 226d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mInitialized = INITIALIZED_NONE; 227510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 228510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // release the closure circular buffer 229d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (tp->mClosureTypical != tp->mClosureArray && NULL != tp->mClosureArray) { 230d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten free(tp->mClosureArray); 231d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mClosureArray = NULL; 232d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 233510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 234510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // release the thread pool 235d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (tp->mThreadTypical != tp->mThreadArray && NULL != tp->mThreadArray) { 236d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten free(tp->mThreadArray); 237d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mThreadArray = NULL; 238d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 239510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 240d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 241d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 242d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenvoid ThreadPool_deinit(ThreadPool *tp) 243d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 244d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ThreadPool_deinit_internal(tp, tp->mInitialized, tp->mMaxThreads); 245d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 246d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 247cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten// Enqueue a closure to be executed later by a worker thread. 248cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten// Note that this raw interface requires an explicit "kind" and full parameter list. 249cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten// There are convenience methods below that make this easier to use. 25085133c817f6f387cd7d072988a8818f18bb53702Jean-Michel TriviSLresult ThreadPool_add(ThreadPool *tp, ClosureKind kind, ClosureHandler_generic handler, 25185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi void *context1, void *context2, void *context3, int parameter1, int parameter2) 252d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 253d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(NULL != tp); 254510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(NULL != handler); 255510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten Closure *closure = (Closure *) malloc(sizeof(Closure)); 256cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten if (NULL == closure) { 257510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten return SL_RESULT_RESOURCE_ERROR; 258cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten } 259cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mKind = kind; 26085133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi switch(kind) { 26185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PPI: 26285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi closure->mHandler.mHandler_ppi = (ClosureHandler_ppi)handler; 26385133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi break; 26485133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PPII: 26585133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi closure->mHandler.mHandler_ppii = (ClosureHandler_ppii)handler; 26685133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi break; 26785133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi case CLOSURE_KIND_PIIPP: 26885133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi closure->mHandler.mHandler_piipp = (ClosureHandler_piipp)handler; 26985133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi break; 27085133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi default: 27185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi SL_LOGE("ThreadPool_add() invalid closure kind %d", kind); 27285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi assert(false); 27385133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi } 274cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mContext1 = context1; 275cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mContext2 = context2; 27685133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi closure->mContext3 = context3; 277cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mParameter1 = parameter1; 278cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten closure->mParameter2 = parameter2; 279d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten int ok; 280d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_lock(&tp->mMutex); 281d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 282510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // can't enqueue while thread pool shutting down 283510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten if (tp->mShutdown) { 284510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 285510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(0 == ok); 286510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten free(closure); 287510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten return SL_RESULT_PRECONDITIONS_VIOLATED; 288510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 289d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten for (;;) { 290d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure **oldRear = tp->mClosureRear; 291d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure **newRear = oldRear; 292d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (++newRear == &tp->mClosureArray[tp->mMaxClosures + 1]) 293d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten newRear = tp->mClosureArray; 294510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // if closure circular buffer is full, then wait for it to become non-full 295d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (newRear == tp->mClosureFront) { 296d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ++tp->mWaitingNotFull; 297d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_wait(&tp->mCondNotFull, &tp->mMutex); 298d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 299510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // can't enqueue while thread pool shutting down 300d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (tp->mShutdown) { 301d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 < tp->mWaitingNotFull); 302d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten --tp->mWaitingNotFull; 303d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 304d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 305510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten free(closure); 306510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten return SL_RESULT_PRECONDITIONS_VIOLATED; 307d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 308d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten continue; 309d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 310d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(NULL == *oldRear); 311d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *oldRear = closure; 312d4b099b83a686a7bb88f5e36c063f5efe623b56dGlenn Kasten tp->mClosureRear = newRear; 313510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // if a worker thread was waiting to dequeue, then suggest that it try again 314d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (0 < tp->mWaitingNotEmpty) { 315d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten --tp->mWaitingNotEmpty; 316d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_signal(&tp->mCondNotEmpty); 317d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 318d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 319d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten break; 320d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 321d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 322d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 323510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten return SL_RESULT_SUCCESS; 324d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 325d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 326510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread when it is ready to accept the next closure to execute 327d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn KastenClosure *ThreadPool_remove(ThreadPool *tp) 328d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 329d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure *pClosure; 330d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten int ok; 331d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_lock(&tp->mMutex); 332d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 333d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten for (;;) { 334d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten // fail if thread pool is shutting down 335d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten if (tp->mShutdown) { 336d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten pClosure = NULL; 337d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten break; 338d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten } 339d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure **oldFront = tp->mClosureFront; 340510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // if closure circular buffer is empty, then wait for it to become non-empty 341d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (oldFront == tp->mClosureRear) { 342d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ++tp->mWaitingNotEmpty; 343d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_wait(&tp->mCondNotEmpty, &tp->mMutex); 344d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 345510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // try again 346d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten continue; 347d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 348510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // dequeue the closure at front of circular buffer 349d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten Closure **newFront = oldFront; 350d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten if (++newFront == &tp->mClosureArray[tp->mMaxClosures + 1]) { 351d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten newFront = tp->mClosureArray; 352d527933b750b107449263fff2c9d870edbfcc520Glenn Kasten } 353d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten pClosure = *oldFront; 354510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(NULL != pClosure); 355510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten *oldFront = NULL; 356d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten tp->mClosureFront = newFront; 357510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // if a client thread was waiting to enqueue, then suggest that it try again 358d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (0 < tp->mWaitingNotFull) { 359d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten --tp->mWaitingNotFull; 360d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_cond_signal(&tp->mCondNotFull); 361d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 362d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 363d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten break; 364d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 365d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten ok = pthread_mutex_unlock(&tp->mMutex); 366d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten assert(0 == ok); 367d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten return pClosure; 368d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 369cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten 370cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten// Convenience methods for applications 371cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn KastenSLresult ThreadPool_add_ppi(ThreadPool *tp, ClosureHandler_ppi handler, 372cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten void *context1, void *context2, int parameter1) 373cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten{ 374cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten // function pointers are the same size so this is a safe cast 37585133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi return ThreadPool_add(tp, CLOSURE_KIND_PPI, (ClosureHandler_generic) handler, 37685133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi context1, context2, NULL, parameter1, 0); 377cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten} 378cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten 379cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn KastenSLresult ThreadPool_add_ppii(ThreadPool *tp, ClosureHandler_ppii handler, 380cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten void *context1, void *context2, int parameter1, int parameter2) 381cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten{ 38285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi // function pointers are the same size so this is a safe cast 38385133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi return ThreadPool_add(tp, CLOSURE_KIND_PPII, (ClosureHandler_generic) handler, 38485133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi context1, context2, NULL, parameter1, parameter2); 38585133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi} 38685133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi 38785133c817f6f387cd7d072988a8818f18bb53702Jean-Michel TriviSLresult ThreadPool_add_piipp(ThreadPool *tp, ClosureHandler_piipp handler, 38885133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi void *cntxt1, int param1, int param2, void *cntxt2, void *cntxt3) 38985133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi{ 39085133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi // function pointers are the same size so this is a safe cast 39185133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi return ThreadPool_add(tp, CLOSURE_KIND_PIIPP, (ClosureHandler_generic) handler, 39285133c817f6f387cd7d072988a8818f18bb53702Jean-Michel Trivi cntxt1, cntxt2, cntxt3, param1, param2); 393cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten} 394