/****************************************************************************
 *
 *  Copyright (C) 2000-2001 RealNetworks, Inc. All rights reserved.
 *
 *  This program is free software.  It may be distributed under the terms
 *  in the file LICENSE, found in the top level of the source distribution.
 *
 */

#ifndef _THREAD_H
#define _THREAD_H

#include "types.h"

#ifdef _UNIX
#include <pthread.h>
typedef pthread_t       threadobj_t;
typedef int             waittimer_t;
#ifndef INFTIM
#define INFTIM (-1) /* Linux uses -1 but doesn't define INFTIM */
#endif
#endif
#ifdef _WIN32
typedef HANDLE  threadobj_t;
typedef DWORD   waittimer_t;
#define INFTIM  INFINITE
#endif

#include "types.h"
#include "tlist.h"
#include "stream.h"
#include "sock.h"
#include "timer.h"

class CMutex
{
private: // Unimplemented
    CMutex( const CMutex& );
    CMutex& operator=( const CMutex& );

public:
    CMutex( void );
    virtual ~CMutex( void );

    void Lock( void );
    void Unlock( void );

private:
#ifdef _UNIX
    pthread_mutex_t m_mutex;
#endif
#ifdef _WIN32
    HANDLE          m_mutex;
#endif
};

class CSemaphore
{
private: // Unimplemented
    CSemaphore( const CSemaphore& );
    CSemaphore& operator=( const CSemaphore& );

public:
    CSemaphore( UINT nCount );
    virtual ~CSemaphore( void );

    void Lock( void );
    void Unlock( void );

private:
#ifdef _UNIX
    pthread_mutex_t m_mutex;
    pthread_cond_t  m_cond;
    UINT            m_count;
#endif
#ifdef _WIN32
    HANDLE          m_semaphore;
#endif
};

/*
 * Initializing a C++ thread object must involve two steps: creating the
 * C++ object and creating the thread.  If we create the thread in the
 * ctor, we are courting disaster because the C++ object is not fully
 * constructed until after the ctor finishes.  If you think this is all
 * theoretical and doesn't apply in real life, consider this:
 *
 *   - GNU g++ will not call a derived virtual function until after
 *     the ctor is done -- it will *always* call the function defined in
 *     the current class.  Been there, done that, spent hours debugging.
 *
 *   - MS Visual C++ warns about using 'this' in the ctor.  Probably
 *     because more than one programmer has been bitten doing it.
 */

class CThread
{
#ifdef _UNIX
    friend void* thread_start( void* );
#endif
#ifdef _WIN32
    friend DWORD WINAPI thread_start( LPVOID );
#endif

private: // Unimplemented
    CThread( const CThread& );
    CThread& operator=( const CThread& );

public:
    CThread( void );
    virtual ~CThread( void );

    void Create( void );

//    void Suspend( void );
//    void Resume( void );

    static CThread* This( void );

protected:
    virtual bool Init( void );
    virtual void Run( void );
    virtual int  Exit( void );

private:
    threadobj_t m_thread;
    int         m_retval;
};

/*
 * CEventThread -- the scheduler
 */

class CEventThread : public CThread
{
public:
    CEventThread( void );
    ~CEventThread( void );

protected:
    virtual void Run( void );
    virtual bool Init( void );
    virtual int  Exit( void );

private:
    friend class CSocket;
    friend class CTimer;
    bool AddStream( CSocket* pSock );
    void DelStream( CSocket* pSock );
    void SetStreamSelect( CSocket* pSock, UINT nWhich );
    void AddTimer( CTimer* pTimer );
    void DelTimer( CTimer* pTimer );

    void    Heapify( UINT32 now, UINT n );

private:
    UINT        m_nSocks;
    UINT        m_nSockAlloc;
    CSocket**   m_ppSocks;
    waitobj_t*  m_pWaitObjs;
    UINT        m_nTimers;
    UINT        m_nTimerAlloc;
    CTimer**    m_ppTimers;
};

#endif //ndef _THREAD_H


syntax highlighted by Code2HTML, v. 0.9.1