// // OpenThread library, Copyright (C) 2002 - 2003 The Open Thread Group // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // // SprocCondition.c++ - C++ Condition class built on sprocs. // ~~~~~~~~~~~~~~~~~~ #include #include "SprocConditionPrivateData.h" #include #include "SharedArena.h" #include "SprocThreadPrivateActions.h" #include #include using namespace OpenThreads; #ifdef DEBUG #define DPRINTF(arg) printf arg; fflush(stdout); #define DPRINTLIST(arg) ConditionDebug::printList arg; fflush(stdout); namespace OpenThreads { class ConditionDebug { friend class Condition; private: static void printList(std::list &pid_list) { std::list::iterator iter; int counter = 0; printf("(SPROC CONDITION %d) ", getpid()); for(iter=pid_list.begin(); iter!=pid_list.end();++iter) { printf("Pid [%d]=%d, ", counter, *iter); ++counter; } printf("\b\n"); } }; } #else #define DPRINTF(arg) #define DPRINTLIST(arg) #endif void condition_alarm_handler(int signal) { //DPRINTF(("(SPROC CONDITION) signal alarm handler called.\n")); sigset(SIGALRM, SIG_DFL); unblockproc(getpid()); } //---------------------------------------------------------------------------- // // Decription: Constructor // // Use: public. // Condition::Condition() { SprocConditionPrivateData *pd = new SprocConditionPrivateData(); _prvData = static_cast(pd); } //---------------------------------------------------------------------------- // // Decription: Destructor // // Use: public. // Condition::~Condition() { SprocConditionPrivateData *pd = static_cast(_prvData); pd->mutex.lock(); DPRINTF(("(SPROC CONDITION) : In destructor\n")); DPRINTLIST((pd->pid_list)); //------------------------------------------------------------------------- // Destroy all remaining in the linked-list of waiters (pids). // pd->pid_list.clear(); delete pd; _prvData = 0; } //---------------------------------------------------------------------------- // // Decription: wait on a condition // // Use: public. // int Condition::wait(Mutex *mutex) { return wait(mutex, 0); } //---------------------------------------------------------------------------- // // Decription: wait on a condition // // Use: public. // int Condition::wait(Mutex *mutex, unsigned long int ms) { unsigned int sec; unsigned int usec; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; pid_t mypid = getpid(); SprocConditionPrivateData *pd = static_cast(_prvData); if(ms != 0) { // Wait for ms milliseconds sec = ms / 1000; usec = (ms % 1000) * 1000; tv.tv_sec = sec; tv.tv_usec = usec; DPRINTF(("(SPROC CONDITION) : PID %d timeout values [%d | %d]\n", mypid, tv.tv_sec, tv.tv_usec)); } pd->mutex.lock(); pd->pid_list.push_front(mypid); pd->mutex.unlock(); DPRINTF(("(SPROC CONDITION) : PID %d going to blockproc\n", mypid)); int status = 0; status = setblockproccnt(mypid, 0); // If we're doing a timout, setup the signal handler to deal with it. if(tv.tv_sec != 0 || tv.tv_usec != 0) { DPRINTF(("(SPROC CONDITION) : PID %d setting timeout condition\n", mypid)); sigset(SIGALRM, condition_alarm_handler); struct timeval recur; recur.tv_sec = 0; recur.tv_usec = 0; itimerval itv; itv.it_interval = recur; itv.it_value = tv; setitimer(ITIMER_REAL, &itv, NULL); } mutex->unlock(); ThreadPrivateActions::ThreadCancelTest(); status = blockproc(mypid); ThreadPrivateActions::ThreadCancelTest(); mutex->lock(); DPRINTF(("(SPROC CONDITION) : PID %d, returned from blockproc %d\n", mypid, status)); //------------------------------------------------------------------------- // Pull the pid from the list // pd->mutex.lock(); DPRINTLIST((pd->pid_list)); #ifndef DEBUG // KLUDGE - can optimized this by just doing -remove()- std::list::iterator iter; iter = pd->pid_list.begin(); while(iter != pd->pid_list.end()) { if(*iter == mypid) { DPRINTF(("(SPROC CONDITION) : PID %d removed itself from the list\n", mypid)); pd->pid_list.remove(mypid); iter = pd->pid_list.begin(); } else { ++iter; } } #else pd->pid_list.remove(mypid); #endif DPRINTLIST((pd->pid_list)); pd->mutex.unlock(); if(status == -1) { return status; } return 0; } //---------------------------------------------------------------------------- // // Decription: signal a thread to wake up. // // Use: public. // int Condition::signal() { ThreadPrivateActions::ThreadCancelTest(); SprocConditionPrivateData *pd = static_cast(_prvData); pd->mutex.lock(); if(pd->pid_list.empty()) { DPRINTF(("(SPROC CONDITION) : No threads to signal\n")); pd->mutex.unlock(); // Remember to release the mutex. return 0; } //------------------------------------------------------------------------- // Perform an unblockproc on the first pid in the list. // DPRINTF(("(SPROC CONDITION) : PID %d signaling pid %d\n", getpid(), pd->pid_list.front())); int status = unblockproc(pd->pid_list.front()); pd->mutex.unlock(); return status; } //---------------------------------------------------------------------------- // // Decription: signal all threads to wake up. // // Use: public. // int Condition::broadcast() { ThreadPrivateActions::ThreadCancelTest(); SprocConditionPrivateData *pd = static_cast(_prvData); pd->mutex.lock(); std::list::iterator iter; for(iter = pd->pid_list.begin(); iter != pd->pid_list.end(); ++iter) { DPRINTF(("(SPROC CONDITION) Broadcast to pid[%d]\n", *iter)); unblockproc(*iter); } pd->mutex.unlock(); return 0; }