/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* .
*
*/
static const char* const Thread_cxx_Version =
"$Id: Thread.cxx,v 1.4 2001/08/10 04:02:08 icahoon Exp $";
#include "global.h"
#include "Thread.hxx"
#include "Runnable.hxx"
#include "SignalHandler.hxx"
#include "Application.hxx"
#include "Lock.hxx"
#include
#include
using Vocal::Threads::Thread;
using Vocal::Threads::Mutex;
using Vocal::Threads::Lock;
using Vocal::Signals::SignalHandler;
using Vocal::Runnable;
using Vocal::ReturnCode;
Thread::ThreadMap * Thread::myThreadMap = 0;
Mutex Thread::myThreadMapMutex;
Thread * Thread::myMainThread = 0;
extern "C"
{
static void *
localThreadMain(void * data)
{
return ( Thread::threadMain(data) );
}
} // extern "C"
void
Thread::init()
{
Lock lock(myThreadMapMutex);
if ( !myThreadMap )
{
myThreadMap = new map;
myMainThread = new Thread;
vthread_t mainThreadId = VThread::selfId();
(*myThreadMap)[mainThreadId] = myMainThread;
}
}
void
Thread::uninit()
{
Lock lock(myThreadMapMutex);
delete myThreadMap;
myThreadMap = 0;
delete myMainThread;
myMainThread = 0;
}
Thread *
Thread::self()
{
init();
Lock lock(myThreadMapMutex);
vthread_t id = VThread::selfId();
assert( myThreadMap != 0 );
ThreadMap::iterator it = myThreadMap->find(id);
return ( it == myThreadMap->end() ? 0 : (*it).second );
}
vthread_t
Thread::selfId()
{
return ( VThread::selfId() );
}
Thread::Thread(Runnable & runnable, const char * name)
: myThread(new VThread),
myRunnable(runnable),
mySignalHandler(0),
myName(name ? name : "thread")
{
init();
myThread->spawn(localThreadMain, this);
}
Thread::~Thread()
{
const vthread_t * threadId = myThread->getId();
if ( threadId )
{
Lock lock(myThreadMapMutex);
if ( myThreadMap )
{
myThreadMap->erase(*threadId);
}
else
{
assert( myThreadMap != 0 );
}
}
delete myThread;
delete mySignalHandler;
}
ReturnCode
Thread::join()
{
// Can't join from your own thread.
//
if ( this == self() )
{
return ( 0 );
}
ReturnCode rc = 0;
if ( myThread )
{
rc = myThread->join();
}
return ( rc );
}
void
Thread::exit()
{
// Can't exit unless this is the thread of execution.
//
if ( myThread == 0 || this != self() )
{
return;
}
myThread->exit();
}
Runnable &
Thread::runnable()
{
return ( myRunnable );
}
SignalHandler &
Thread::signalHandler()
{
assert( mySignalHandler != 0 );
return ( *mySignalHandler );
}
ostream &
Thread::writeTo(ostream & out) const
{
return ( out << myName.c_str() );
}
Thread::Thread()
: myThread(0),
myRunnable(Application::instance()),
mySignalHandler(new SignalHandler),
myName("main")
{
char buffer[64];
sprintf(buffer, "%lu", (unsigned long)VThread::selfId());
myName += '.';
myName += buffer;
}
void *
Thread::threadMain(void * data)
{
Thread * thread = (Thread *)data;
if ( thread == 0 )
{
return ( (void *)1 );
}
const vthread_t * threadId = thread->myThread->getId();
// Scope the lock for update of thread map only.
//
{
Lock lock(myThreadMapMutex);
if ( myThreadMap )
{
(*myThreadMap)[*threadId] = thread;
}
else
{
assert( myThreadMap != 0 );
return ( (void *)1 );
}
}
// Update name
//
char buffer[64];
sprintf(buffer, "%lu", (unsigned long)*threadId);
thread->myName += '.';
thread->myName += buffer;
// The signalHandler will persist for the lifetime of the run.
//
thread->mySignalHandler = new SignalHandler;
void * rc = (void *)(thread->myRunnable.run());
delete thread->mySignalHandler;
thread->mySignalHandler = 0;
return ( rc );
}