// @(#)root/thread:$Id$
// 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. Returns 0 on success, otherwise an error number will
   // be returned.

   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);

   // See e.g. https://developer.apple.com/library/mac/#qa/qa1419/_index.html
   // MacOS has only 512k of stack per thread; Linux has 2MB.
   const size_t requiredStackSize = 1024*1024*2;
   size_t stackSize = 0;
   if (!pthread_attr_getstacksize(attr, &stackSize)
       && stackSize < requiredStackSize) {
      pthread_attr_setstacksize(attr, requiredStackSize);
   }
   int ierr = pthread_create(&id, attr, &TThread::Function, th);
   if (!ierr) th->fId = (Long_t) id;

   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. Returns 0 on success, otherwise an error number will
   // be returned.

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

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

   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. Returns 0 on success, otherwise an error
   // number will be returned.

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

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOff()
{
   // Turn off the cancellation state of the calling thread. Returns 0 on
   // success, otherwise an error number will be returned.

   return pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
}

//______________________________________________________________________________
Int_t TPosixThread::SetCancelOn()
{
   // Turn on the cancellation state of the calling thread. Returns 0 on
   // success, otherwise an error number will be returned.

   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.
   // Returns 0 on success, otherwise an error number will be returned.

   return pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, 0);
}

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

   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)
{
   //cleanup function
   fNext = (TPosixThreadCleanUp*)*main;
   fRoutine = routine; fArgument = arg;
   *main  = this;
}
 TPosixThread.cxx:1
 TPosixThread.cxx:2
 TPosixThread.cxx:3
 TPosixThread.cxx:4
 TPosixThread.cxx:5
 TPosixThread.cxx:6
 TPosixThread.cxx:7
 TPosixThread.cxx:8
 TPosixThread.cxx:9
 TPosixThread.cxx:10
 TPosixThread.cxx:11
 TPosixThread.cxx:12
 TPosixThread.cxx:13
 TPosixThread.cxx:14
 TPosixThread.cxx:15
 TPosixThread.cxx:16
 TPosixThread.cxx:17
 TPosixThread.cxx:18
 TPosixThread.cxx:19
 TPosixThread.cxx:20
 TPosixThread.cxx:21
 TPosixThread.cxx:22
 TPosixThread.cxx:23
 TPosixThread.cxx:24
 TPosixThread.cxx:25
 TPosixThread.cxx:26
 TPosixThread.cxx:27
 TPosixThread.cxx:28
 TPosixThread.cxx:29
 TPosixThread.cxx:30
 TPosixThread.cxx:31
 TPosixThread.cxx:32
 TPosixThread.cxx:33
 TPosixThread.cxx:34
 TPosixThread.cxx:35
 TPosixThread.cxx:36
 TPosixThread.cxx:37
 TPosixThread.cxx:38
 TPosixThread.cxx:39
 TPosixThread.cxx:40
 TPosixThread.cxx:41
 TPosixThread.cxx:42
 TPosixThread.cxx:43
 TPosixThread.cxx:44
 TPosixThread.cxx:45
 TPosixThread.cxx:46
 TPosixThread.cxx:47
 TPosixThread.cxx:48
 TPosixThread.cxx:49
 TPosixThread.cxx:50
 TPosixThread.cxx:51
 TPosixThread.cxx:52
 TPosixThread.cxx:53
 TPosixThread.cxx:54
 TPosixThread.cxx:55
 TPosixThread.cxx:56
 TPosixThread.cxx:57
 TPosixThread.cxx:58
 TPosixThread.cxx:59
 TPosixThread.cxx:60
 TPosixThread.cxx:61
 TPosixThread.cxx:62
 TPosixThread.cxx:63
 TPosixThread.cxx:64
 TPosixThread.cxx:65
 TPosixThread.cxx:66
 TPosixThread.cxx:67
 TPosixThread.cxx:68
 TPosixThread.cxx:69
 TPosixThread.cxx:70
 TPosixThread.cxx:71
 TPosixThread.cxx:72
 TPosixThread.cxx:73
 TPosixThread.cxx:74
 TPosixThread.cxx:75
 TPosixThread.cxx:76
 TPosixThread.cxx:77
 TPosixThread.cxx:78
 TPosixThread.cxx:79
 TPosixThread.cxx:80
 TPosixThread.cxx:81
 TPosixThread.cxx:82
 TPosixThread.cxx:83
 TPosixThread.cxx:84
 TPosixThread.cxx:85
 TPosixThread.cxx:86
 TPosixThread.cxx:87
 TPosixThread.cxx:88
 TPosixThread.cxx:89
 TPosixThread.cxx:90
 TPosixThread.cxx:91
 TPosixThread.cxx:92
 TPosixThread.cxx:93
 TPosixThread.cxx:94
 TPosixThread.cxx:95
 TPosixThread.cxx:96
 TPosixThread.cxx:97
 TPosixThread.cxx:98
 TPosixThread.cxx:99
 TPosixThread.cxx:100
 TPosixThread.cxx:101
 TPosixThread.cxx:102
 TPosixThread.cxx:103
 TPosixThread.cxx:104
 TPosixThread.cxx:105
 TPosixThread.cxx:106
 TPosixThread.cxx:107
 TPosixThread.cxx:108
 TPosixThread.cxx:109
 TPosixThread.cxx:110
 TPosixThread.cxx:111
 TPosixThread.cxx:112
 TPosixThread.cxx:113
 TPosixThread.cxx:114
 TPosixThread.cxx:115
 TPosixThread.cxx:116
 TPosixThread.cxx:117
 TPosixThread.cxx:118
 TPosixThread.cxx:119
 TPosixThread.cxx:120
 TPosixThread.cxx:121
 TPosixThread.cxx:122
 TPosixThread.cxx:123
 TPosixThread.cxx:124
 TPosixThread.cxx:125
 TPosixThread.cxx:126
 TPosixThread.cxx:127
 TPosixThread.cxx:128
 TPosixThread.cxx:129
 TPosixThread.cxx:130
 TPosixThread.cxx:131
 TPosixThread.cxx:132
 TPosixThread.cxx:133
 TPosixThread.cxx:134
 TPosixThread.cxx:135
 TPosixThread.cxx:136
 TPosixThread.cxx:137
 TPosixThread.cxx:138
 TPosixThread.cxx:139
 TPosixThread.cxx:140
 TPosixThread.cxx:141
 TPosixThread.cxx:142
 TPosixThread.cxx:143
 TPosixThread.cxx:144
 TPosixThread.cxx:145
 TPosixThread.cxx:146
 TPosixThread.cxx:147
 TPosixThread.cxx:148
 TPosixThread.cxx:149
 TPosixThread.cxx:150
 TPosixThread.cxx:151
 TPosixThread.cxx:152
 TPosixThread.cxx:153
 TPosixThread.cxx:154
 TPosixThread.cxx:155
 TPosixThread.cxx:156
 TPosixThread.cxx:157
 TPosixThread.cxx:158
 TPosixThread.cxx:159
 TPosixThread.cxx:160
 TPosixThread.cxx:161
 TPosixThread.cxx:162
 TPosixThread.cxx:163
 TPosixThread.cxx:164
 TPosixThread.cxx:165
 TPosixThread.cxx:166
 TPosixThread.cxx:167
 TPosixThread.cxx:168
 TPosixThread.cxx:169
 TPosixThread.cxx:170
 TPosixThread.cxx:171
 TPosixThread.cxx:172
 TPosixThread.cxx:173
 TPosixThread.cxx:174
 TPosixThread.cxx:175
 TPosixThread.cxx:176
 TPosixThread.cxx:177
 TPosixThread.cxx:178
 TPosixThread.cxx:179
 TPosixThread.cxx:180
 TPosixThread.cxx:181
 TPosixThread.cxx:182
 TPosixThread.cxx:183
 TPosixThread.cxx:184
 TPosixThread.cxx:185
 TPosixThread.cxx:186
 TPosixThread.cxx:187
 TPosixThread.cxx:188
 TPosixThread.cxx:189
 TPosixThread.cxx:190
 TPosixThread.cxx:191
 TPosixThread.cxx:192
 TPosixThread.cxx:193
 TPosixThread.cxx:194
 TPosixThread.cxx:195
 TPosixThread.cxx:196
 TPosixThread.cxx:197