blob: 9f17845b94782accc57e2ddaf547cd25ed757b55 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Thread.h"
#ifdef HAVE_PTHREAD_H
#include <errno.h>
#else
#include <process.h> // _endthreadex
#endif
#include <activemq/exceptions/ActiveMQException.h>
#include <activemq/exceptions/RuntimeException.h>
using namespace activemq;
using namespace activemq::concurrent;
////////////////////////////////////////////////////////////////////////////////
Thread::Thread()
{
task = this;
started = false;
joined = false;
}
////////////////////////////////////////////////////////////////////////////////
Thread::Thread( Runnable* task )
{
this->task = task;
started = false;
joined = false;
}
////////////////////////////////////////////////////////////////////////////////
Thread::~Thread()
{
}
////////////////////////////////////////////////////////////////////////////////
void Thread::start() throw ( exceptions::ActiveMQException )
{
if (this->started) {
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"Thread already started");
}
#ifdef HAVE_PTHREAD_H
::pthread_attr_init (&attributes);
::pthread_attr_setdetachstate (&attributes, PTHREAD_CREATE_JOINABLE);
int err = ::pthread_create (
&this->threadHandle,
&attributes,
runCallback,
this);
if (err != 0) {
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"Coud not start thread");
}
#else
unsigned int threadId = 0;
this->threadHandle =
(HANDLE)::_beginthreadex(NULL, 0, runCallback, this, 0, &threadId);
if (this->threadHandle == NULL) {
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"Coud not start thread");
}
#endif
// Mark the thread as started.
started = true;
}
////////////////////////////////////////////////////////////////////////////////
void Thread::join() throw( exceptions::ActiveMQException )
{
if (!this->started) {
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"Thread::join() called without having called Thread::start()");
}
if (!this->joined) {
#ifdef HAVE_PTHREAD_H
::pthread_join(this->threadHandle, NULL);
#else
::WaitForSingleObject (this->threadHandle, INFINITE);
#endif
}
this->joined = true;
}
////////////////////////////////////////////////////////////////////////////////
void Thread::sleep( int millisecs )
{
#ifdef HAVE_PTHREAD_H
struct timespec rec, rem;
rec.tv_sec = millisecs / 1000;
rec.tv_nsec = (millisecs % 1000) * 1000000;
while( nanosleep( &rec, &rem ) == -1 ){
if( errno != EINTR ){
break;
}
}
#else
::Sleep (millisecs);
#endif
}
////////////////////////////////////////////////////////////////////////////////
unsigned long Thread::getId(void)
{
#ifdef HAVE_PTHREAD_H
return (long)(pthread_self());
#else
return GetCurrentThreadId();
#endif
}
////////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_PTHREAD_H
void*
#else
unsigned int WINAPI
#endif
Thread::runCallback( void* param )
{
// Get the instance.
Thread* thread = (Thread*)param;
// Invoke run on the task.
try{
thread->task->run();
} catch( ... ){
exceptions::RuntimeException ex(__FILE__, __LINE__, "unhandled exception bubbled up to Thread::run");
ex.printStackTrace();
}
#ifdef HAVE_PTHREAD_H
::pthread_attr_destroy( &thread->attributes );
return NULL;
#else
// Needed when using threads and CRT in Windows. Otherwise memleak can appear.
::_endthreadex(0);
// _endthreadex (unlike _endthread) does not automatically close the thread handle
// so we need to do this manually.
::CloseHandle(thread->threadHandle);
return 0;
#endif
}