    // @(#)root/thread:$Name:  $:$Id: TPosixThread.cxx,v 1.11 2005/01/05 01:25:19 rdm Exp $
    // Author: Fons Rademakers   02/07/97

    /*************************************************************************
     * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // TPosixThread                                                         //
    //                                                                      //
    // This class provides an interface to the posix thread routines.       //
    //                                                                      //
    //////////////////////////////////////////////////////////////////////////

    #include "TPosixThread.h"

    ClassImp(TPosixThread)

    //______________________________________________________________________________
     Int_t TPosixThread::Run(TThread *th)
    {
       // Create a pthread.

       int det;
       pthread_t id;
       pthread_attr_t *attr = new pthread_attr_t;

       pthread_attr_init(attr);

       // Set detach state
       det = (th->fDetached) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;

       pthread_attr_setdetachstate(attr, det);
       int ierr = pthread_create(&id, attr, &TThread::Function, th);
       if (!ierr) th->fId = (Long_t) id;
       if (attr) {
          pthread_attr_destroy(attr);
          delete attr;
       }
       return ierr;
    }

    //______________________________________________________________________________
     Int_t TPosixThread::Join(TThread *th, void **ret)
    {
       // Join  suspends  the  execution  of the calling thread until the
       // thread identified by th terminates, either by  calling  pthread_exit
       // or by being cancelled.

       return pthread_join((pthread_t) th->fId, ret);
    }

    //______________________________________________________________________________
     Int_t TPosixThread::Exit(void *ret)
    {
       // Terminates the execution of the calling thread.

       pthread_exit(ret);
       return 0;
    }

    //______________________________________________________________________________
     Int_t TPosixThread::Kill(TThread *th)
    {
       // Cancellation is the mechanism by which a thread can terminate the
       // execution of another thread.

       return pthread_cancel((pthread_t) th->fId);
    }

    //______________________________________________________________________________
     Int_t TPosixThread::SetCancelOff()
    {
       // Turn off the cancellation state of the calling thread.

       return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
    }

    //______________________________________________________________________________
     Int_t TPosixThread::SetCancelOn()
    {
       // Turn on the cancellation state of the calling thread.

       return pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
    }

    //______________________________________________________________________________
     Int_t TPosixThread::SetCancelAsynchronous()
    {
       // Set the cancellation response type of the calling thread to
       // asynchronous, i.e. cancel as soon as the cancellation request
       // is received.

       return pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
    }

    //______________________________________________________________________________
     Int_t TPosixThread::SetCancelDeferred()
    {
       // Set the cancellation response type of the calling thread to
       // deferred, i.e. cancel only at next cancellation point.

       return pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, 0);
    }

    //______________________________________________________________________________
     Int_t TPosixThread::CancelPoint()
    {
       // Introduce an explicit cancellation point.

       int istate;
       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &istate);
       pthread_testcancel();
       pthread_setcancelstate(istate, 0);

       return 0;
    }

    //______________________________________________________________________________
     Int_t TPosixThread::CleanUpPush(void **main, void *free, void *arg)
    {
       // Add thread cleanup function.

       // pthread_cleanup_push(free, arg);
       if (!free) Error("CleanUpPush", "cleanup rountine = 0");
       new TPosixThreadCleanUp(main, free, arg);
       return 0;
    }

    //______________________________________________________________________________
     Int_t TPosixThread::CleanUpPop(void **main,Int_t exe)
    {
       // Pop thread cleanup function from stack.

       //  pthread_cleanup_pop(exe); // happy pthread future

       if (!main || !*main) return 1;
       TPosixThreadCleanUp *l = (TPosixThreadCleanUp*)(*main);
       if (!l->fRoutine) Error("CleanUpPop", "cleanup routine = 0");
       if (exe && l->fRoutine) ((void (*)(void*))(l->fRoutine))(l->fArgument);
       *main = l->fNext;  delete l;
       return 0;
    }

    //______________________________________________________________________________
     Int_t TPosixThread::CleanUp(void **main)
    {
       // Default thread cleanup routine.

       if (gDebug > 0)
          Info("Cleanup", "cleanup 0x%lx", (Long_t)*main);
       while (!CleanUpPop(main, 1)) { }
       return 0;
    }

    //______________________________________________________________________________
     Long_t TPosixThread::SelfId()
    {
       // Return the thread identifier for the calling thread.

       return (Long_t) pthread_self();
    }

    //   Clean Up section. PTHREAD implementations of cleanup after cancel are
    //   too different and often too bad. Temporary I invent my own bicycle.
    //                                                              V.Perev.

    //______________________________________________________________________________
    TPosixThreadCleanUp::TPosixThreadCleanUp(void **main, void *routine, void *arg)
    {
       fNext = (TPosixThreadCleanUp*)*main;
       fRoutine = routine; fArgument = arg;
       *main  = this;
    }