/*
 Copyright (C) 2002 Andreas Thiede ( a.thiede@berlin.de )

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <IO/Manager/IOThread.hpp>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>

IOThread::IOThread( const string & aName, bool useRT )
 : IOObject( aName, "IOThread" ), mUseRT( useRT )
{
    init();
}
    
IOThread::~IOThread()
{
    finit();
}
 
bool IOThread::isRunning()   
{
    lock();
    
    bool result = ( mState == ioRunning );
    
    unlock();
    
    return result;
}

bool IOThread::isPaused()   
{
    lock();
    
    bool result = ( mState == ioPaused );
    
    unlock();
    
    return result;
}

IOThread::Request IOThread::serviceCancellation()
{
    if( pthread_self() == mWorkThread ) {

        lock();

        Request request = mRequest;
        
        if( mRequest == ioPause ) {
        
            mState = ioPaused;
    
            
            wait();
        
            mState = ioRunning;
        
            mRequest = ioNullRequest;
        }
                
        unlock();
        
        return request;
    }
    else {
        return ioNullRequest;
    }
}

static void * threadEntry( void * _this )
{
    ((IOThread*) _this )->threadStartRoutine();
        
    return 0;
}

void IOThread::threadStartRoutine()
{
    mState = ioRunning;
    
    mEntry( mArg );

    mState = ioStopped;
}

bool IOThread::start( void *(*startRoutine)(void *), void *arg  )
{
    if( pthread_self() == mWorkThread ) {
        return false;
    }
    
    if( mState != ioRunning ) {

        mState    = ioCreated;
        mRequest  = ioNullRequest;

        mEntry = startRoutine;

        mArg   = arg;
        
        pthread_attr_t attr;
        
        pthread_attr_init( &attr );
    
        if( mUseRT ) {
            pthread_attr_setschedpolicy( &attr, SCHED_RR );
        }
        else {
            pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
        }
        
        pthread_create( &mWorkThread, &attr, threadEntry, this );
    
        while( mState != ioRunning ) {
            usleep( 100 * 1000 );
        }        
        pthread_attr_destroy( &attr );
    }

    return mState == ioRunning;
}

bool IOThread::pause()
{
    if( pthread_self() == mWorkThread ) {
        return false;
    }

    if( mState == ioRunning && mRequest == ioNullRequest ) {
    
        mRequest = ioPause;
    
        while( mState != ioPaused ) {
            usleep( 100 * 1000 );
        }     
        return true;        
    }
    return false;
}

bool IOThread::resume()
{
    if( pthread_self() == mWorkThread ) {
        return false;
    }

    signal();
    
    return true;
}

bool IOThread::stop()
{
    if( pthread_self() == mWorkThread ) {
        return false;
    }

    switch( mState ) {
    
    case ioRunning:
    case ioPaused:
    
        mRequest = ioStop;

        if( mState == ioPaused ) {
            resume();
        }
        
        while( mState != ioStopped ) {
            usleep( 100 * 1000 );
        }  
        
        break;
    default:
        break;
    }
    
    return ( mState == ioStopped );
}

void IOThread::finit()
{
    stop();
}

void IOThread::init()
{    
    mState = ioCreated;
}
