thread.h
上传用户:shtangtang
上传日期:2007-01-04
资源大小:167k
文件大小:16k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /***************************************************************************
  2.  *                                                                         *
  3.  *   This program is free software; you can redistribute it and/or modify  *
  4.  *   it under the terms of the GNU General Public License as published by  *
  5.  *   the Free Software Foundation; either version 2 of the License, or     *
  6.  *   (at your option) any later version.                                   * 
  7.  *                                                                         *
  8.  ***************************************************************************/
  9. /**
  10.  * Copyright (c) 1999
  11.  *
  12.  * A C++ implementation of posix threads, using Linux clone system
  13.  * calls.
  14.  *
  15.  * The implementation is identical to the implementation found in
  16.  * the linuxthreads package, except that each thread is an object
  17.  * here.
  18.  *
  19.  * Using Linux pthread package, has a rather bad
  20.  * bi-effect in C++.  When a routine, is called
  21.  * inside a class, it looses it's scope on the
  22.  * class.  That is, the 'this' pointer.  This
  23.  * superclass is to remedy that.
  24.  *
  25.  * @author Orn Hansen <oe.hansen@gamma.telenordia.se>
  26.  * @short a C++ implementation of threads for linux.
  27.  */
  28. #ifndef __THREADS_LIBRARY_H
  29. #define __THREADS_LIBRARY_H
  30. #define _THREAD_SAFE
  31. #define DEFAULTMUTEX        mutex_t()
  32. class mutex;
  33. class cond;
  34. class spinlock;
  35. typedef mutex               mutex_t;
  36. typedef cond                cond_t;
  37. typedef spinlock            spinlock_t;
  38. #define mutex_lock(x)       ((mutex_t *)x)->lock()
  39. #define mutex_unlock(x)     ((mutex_t *)x)->unlock()
  40. #include <thread_alloc.h>
  41. #include <thread_mutex.h>
  42. #include <thread_cond.h>
  43. #include <thread_semaphore.h>
  44. extern "C" {
  45. #  include <setjmp.h>
  46. #  include <unistd.h>
  47. };
  48. #ifndef PTHREAD_CANCELED
  49. #define PTHREAD_CANCELED           ((void *)-1)
  50. #endif
  51. #define PTHREAD_SIG_RESTART        s_user1
  52. #define PTHREAD_SIG_CANCEL         s_user2
  53. /**
  54.  * Threads, are cloned processes that share the same
  55.  * memory for reading and writing.  This is a primitive
  56.  * and needs to be a superclass to any specific needs for
  57.  * threaded execution.
  58.  *
  59.  * @short Abstract class for threads.
  60.  * @author Orn Hansen <oe.hansen@gamma.telenordia.se>
  61.  */
  62. class pthread {
  63.  public:
  64.   enum cancel_state {
  65.     cancel_enable,
  66.     cancel_disable
  67.   };
  68.   enum cancel_type {
  69.     cancel_deferred,
  70.     cancel_asynchronous
  71.   };
  72.   enum jumps {
  73.     signal_jmp,
  74.     cancel_jmp
  75.   };
  76.   enum booleans {
  77.     set_terminated,
  78.     set_detached,
  79.     set_exited,
  80.     set_canceled,
  81.     set_private
  82.   };
  83.  private:
  84.   int             p_id;
  85.   char*           p_sp;
  86.   spinlock        p_spinlock;
  87.   attributes      p_attributes;
  88.   int             p_priority;
  89.   int             p_signal;
  90.   int             p_joining;
  91.   int             p_errno;
  92.   void*           p_retval;
  93.   int             p_retcode;
  94.   sigjmp_buf*     p_signal_jmp;
  95.   sigjmp_buf*     p_cancel_jmp;
  96.   bool            p_terminated;
  97.   bool            p_exited;
  98.   cancel_state    p_cancelstate;
  99.   cancel_type     p_canceltype;
  100.   bool            p_canceled;
  101.   void varinit();
  102.   void invoke(void *);
  103.   bool error(int val)               { p_errno = val; return false; };
  104.  public:
  105.   pthread();
  106.   pthread(void *);
  107.   pthread(int);
  108.   virtual ~pthread();
  109.   /**
  110.    * An abstract definition of the method, that will be run
  111.    * as a different process by this class.  This is the starting
  112.    * point, of the new process.
  113.    *
  114.    * In creating a new process, it should be taken care off that
  115.    * the process itself, is starting its execution at the same
  116.    * time as the construction is initializing class variables.  This
  117.    * may be unwanted, and to have a process wait for the initialization
  118.    * to finish, the following method can be used.
  119.    *
  120.    * <pre>
  121.    *
  122.    * #include <thread.h>
  123.    *
  124.    * class mythread : public pthread {
  125.    * private:
  126.    *   semaphore run_away;
  127.    *   string something;
  128.    *
  129.    * public:
  130.    *   mythread()
  131.    *   {
  132.    *     something = "This has been initialized";
  133.    *     run_away.post();   // last instruction in constructor.
  134.    *   }
  135.    *   ~mythread()
  136.    *   {
  137.    *      // TODO: destroy variables.
  138.    *   }
  139.    *
  140.    *   int thread(void *)
  141.    *   {
  142.    *      run_away.wait();
  143.    *      // Now, the process is synchronized to run after
  144.    *      // the initialisation has finished.
  145.    *   }
  146.    * };
  147.    *
  148.    * </pre>
  149.    *
  150.    * The above mechanism, can both be seen as a quirk, and as a drawback.
  151.    * In most cases, the thread doesn't need the variables in its class,
  152.    * so forcing the thread to wait until the constructor has finished
  153.    * isn't necessary... and perhaps even unwanted.
  154.    *
  155.    * @param any The process will receive a parameter, whose type is only known internally.
  156.    * @return Actually, nothing is returned here.  See @ref #retval how to acquire return values.
  157.    */
  158.   virtual int thread(void *)        = 0;
  159.   /**
  160.    * This method allows access to the value returned by the process, if
  161.    * it has returned, that is.  Otherwise, it contains an undefined value.
  162.    *
  163.    * @return A pointer, that the thread can register as a return value.
  164.    */
  165.   void *retval() const              { return p_retval; };
  166.   /**
  167.    * This method defines, wether the thread is joining with another
  168.    * thread.  The return value, is either the process id of the
  169.    * thread that is to be joined with, or 0 which indicates that
  170.    * it is not being joined with anyone.
  171.    *
  172.    * @return the pid of the process to join with.
  173.    */
  174.   int  joining() const              { return p_joining; };
  175.   /**
  176.    * If an error has occurred, during the process, it will be locally
  177.    * stored and can be retrieved by this method.  Note however, that
  178.    * it is upon the user to make sure that his thread sets this value
  179.    * with the @ref #error function.
  180.    *
  181.    * @return The last errorvalue registered.
  182.    */
  183.   int  gerrno() const               { return p_errno; };
  184.   /**
  185.    * Each thread has its own process id, and even though it is
  186.    * possible with the clone system to clone the process id as well,
  187.    * it is not done within this thread package.
  188.    *
  189.    * @return the pid of this thread.
  190.    */
  191.   int  id() const                   { return p_id; };
  192.   /** 
  193.    * Each time a thread receives a signal, it stores the
  194.    * signal number locally so that parent threads can view
  195.    * or debug its status.
  196.    *
  197.    * @return Last signal received by the thread.
  198.    */
  199.   int  signal() const               { return p_signal; };
  200.   /**
  201.    * This is a convenience function, provided to simplify the
  202.    * use of sending signals to a thread.  If the user has access to
  203.    * the thread class, he can use this method to signal the thread
  204.    * instead of the system kill function.
  205.    *
  206.    * @return Last signal received by the thread.
  207.    */
  208.   int  signal(int);
  209.   /**
  210.    * A running thread can terminate in several ways, it can
  211.    * terminate by returning or exiting from the thread, or it
  212.    * can be canceled from inside or from an outside source.
  213.    * This function reports if the thread was canceled.
  214.    *
  215.    * @return True if the thread has been canceled.
  216.    */
  217.   bool canceled() const             { return p_canceled; };
  218.   /**
  219.    * Usually all threads created by the main program will be
  220.    * hanging on to it.  This means, that when the main program
  221.    * stops execution, the thread belonging to it will be
  222.    * terminated when it exits.  The thread can however detach
  223.    * itself from the main thread.
  224.    *
  225.    * @return True if the thread has been detached.
  226.    */
  227.   bool detached() const;
  228.   /**
  229.    * A detached thread, isn't joinable... there may also be
  230.    * other situations where a thread does not want a parent
  231.    * thread to join onto it.
  232.    *
  233.    * @return True if the thread can be joined with.
  234.    */
  235.   bool joinable() const;
  236.   /**
  237.    * If a thread has terminated its run, this status will
  238.    * be stored for parent threads to examine.
  239.    *
  240.    * @return True if the thread has terminated its running loop. 
  241.    */
  242.   bool terminated() const           { return p_terminated; };
  243.   /**
  244.    * There are several ways, as previously mentioned, for a thread
  245.    * to finish.  One way, is that it uses the 'exit()' call belonging
  246.    * to the class, another that it simply 'returns' from the
  247.    * loop.
  248.    *
  249.    * @return True, if the thread has exited with 'exit'.
  250.    */
  251.   bool exited() const               { return p_exited; };
  252.   /**
  253.    * Return the cancel state of the process.  The process
  254.    * can disable cancelation, which will make it useful to
  255.    * be able to check if it is actually possible to cancel
  256.    * it.  The cancel state can be one of:
  257.    *
  258.    * <pre>
  259.    * cancel_enable   - The process can be cancelled.
  260.    * cancel_disable  - The process cannot be cancelled.
  261.    * </pre>
  262.    *
  263.    * @return The cancel state.
  264.    */
  265.   cancel_state cancelstate() const  { return p_cancelstate; };
  266.   /**
  267.    * If cancels occur, the process can treat them in one of
  268.    * two ways.  It can be handled asynchronously, or it can
  269.    * deferred.  Cancel type, is thus one of:
  270.    *
  271.    * <pre>
  272.    * cancel_deferred      - Cancels are deferred.
  273.    * cancel_asynchronous  - Asynchronous cancels.
  274.    * </pre>
  275.    *
  276.    * @return the cancel type.
  277.    */
  278.   cancel_type canceltype() const    { return p_canceltype; };
  279.   /**
  280.    * Join this thread, with another thread.  When this
  281.    * thread terminates, the joined process will be signalled
  282.    * to revive it from a slumber, as a result.
  283.    *
  284.    * @param pid The pid of the process to revive on exit.
  285.    * @return The pid that was set.
  286.    */
  287.   int joining(int s)                { return p_joining = s; };
  288.   /**
  289.    * Set the cancelation state for this thread, see
  290.    * @ref #cancelstate for a discussion on the states available.
  291.    */
  292.   void set(cancel_state s)          { p_cancelstate = s; };
  293.   /**
  294.    * Set the cancelation type for this thread, see
  295.    * @ref #canceltype for a discussion on the types that
  296.    * are available.
  297.    */
  298.   void set(cancel_type t)           { p_canceltype = t; };
  299.   /**
  300.    * Set the points to jump to, on cancel or signal signals.  The
  301.    * jump types are:
  302.    *
  303.    * <pre>
  304.    * cancel_jmp   - When a cancel signal occurs.
  305.    * signal_jmp   - On a normal signal.
  306.    * </pre>
  307.    *
  308.    * @param jump the jump kind, as above.
  309.    * @param sigjmp The jump point to set.
  310.    */
  311.   void set(jumps, sigjmp_buf *);
  312.   /**
  313.    * Set any of the boolean variables this thread contains.  The
  314.    * following are for use:
  315.    *
  316.    * <pre>
  317.    * set_canceled       - Signify cancel state.
  318.    * set_terminated     - Signify termination state.
  319.    * set_detached       - Signify detached state.
  320.    * set_exited         - Signify exited state.
  321.    * </pre>
  322.    * 
  323.    * The state can only be set, by the process owner.  In this case,
  324.    * the thread itself.
  325.    * @param type The type, as above.
  326.    * @param bool A boolean value, to set to.
  327.    */
  328.   void set(booleans, bool);
  329.   /**
  330.    * Cancel the process.  This will halt the threads execution,
  331.    * set the cancel state to cancel.  If the cancel type is
  332.    * asynchronous, it will also exit the main loop with an exit
  333.    * value of -1, else if the cancel type is deferred it will
  334.    * jump to a location specified.
  335.    */
  336.   void cancel();
  337.   /**
  338.    * Suspend the process.  The process is halted, but not
  339.    * terminated... a suspended process cannot be cancelled,
  340.    * unless it has been suspended with that in mind
  341.    * see @ref #suspend_with_cancellation
  342.    * The process will be restarted,  upon receiving a restart
  343.    * signal see @ref #restart
  344.    */
  345.   static void suspend();
  346.   /**
  347.    * suspend the calling process, until it is cancelled or
  348.    * receives a signal.  This does the same thing as @ref #suspend
  349.    * but unlike it, the thread can be cancelled when waiting
  350.    * for a signal inside this function.
  351.    */
  352.   static void suspend_with_cancelation();
  353.   /**
  354.    * restart the thread, associated with the class instance.  This
  355.    * will in effect send a SIGUSR1 signal to the process, which will
  356.    * wake it up, if it is in a suspended state or otherwise won't
  357.    * do a thing.
  358.    */
  359.   void restart();
  360.   /**
  361.    * Jump to a given location, look at @ref #set for a discussion on
  362.    * how to set the location to jump to.
  363.    */
  364.   void jump(jumps);
  365.   /**
  366.    * exit the process, with a given return value.  This will only
  367.    * work if the calling process is the same as the thread running
  368.    * inside the class instance.  Calling this function from a
  369.    * parent thread, will not have any effect on this class's thread
  370.    * but rather on the calling thread.
  371.    */
  372.   void exit(void *);
  373.   /**
  374.    * exit the process as above, but give a retcode as a result
  375.    * insteaad of a pointer to a return value.
  376.    */
  377.   void exit(int);
  378.   /**
  379.    * exit the process as above, but give the normal zero return
  380.    * value.
  381.    */
  382.   void exit()                       { this->exit(0); };
  383.   /**
  384.    * If a thread exits with 'return val' from inside the thread
  385.    * function, the return value will be stored and retreivable
  386.    * through this function.
  387.    *
  388.    * @return The return value of the thread.
  389.    */
  390.   int retcode();
  391.   /**
  392.    * Tell if the process of the thread instance is running.  This
  393.    * function is really not very useful, it calls the scheduler
  394.    * to see if it has the thread scheduled.  Which the scheduler
  395.    * does, even if the thread is a zombie.  See @ref #terminated
  396.    * and @ref #cancelled for different methods in determining
  397.    * wether the thread is still alive.
  398.    */
  399.   bool running();
  400.   /**
  401.    * Join the calling process, with the thread instance.  This
  402.    * will suspend the calling process, until the thread has
  403.    * terminated.  The call can return one of the following
  404.    * error values:
  405.    *
  406.    * <pre>
  407.    *  EDLCK         - Dead lock would occur.
  408.    *  ESRCH         - The process is not in the list.
  409.    *  EINVAL        - The thread is detached, or already joining another.
  410.    *  0             - The thread has terminated.
  411.    * </pre>
  412.    * @return err A value, as seen above.
  413.    */
  414.   int join();
  415.   /**
  416.    * In a shared environment, each process must have it's system wide
  417.    * project name that uniquely identifies it and enables other
  418.    * processes to identify its resources for sharing.  This method is
  419.    * provided to change the current project identity to your hearts
  420.    * desire.
  421.    *
  422.    * Note: these project id's will be created as filenames inside
  423.    * the tmp directory, during the process run.  This is done because
  424.    * the shared memory key scheme want's an inode number for use in
  425.    * shared memory key creation.
  426.    *
  427.    * @param str A C string, giving the name of a common project.
  428.    */
  429.   static void set_project(const char *);
  430.   /**
  431.    * In creating a project, the default permission scheme used is
  432.    * RW-R--R-- i.e. Read Write for the user, and Read permission for
  433.    * everyone else.  The user however, may want a different scheme
  434.    * in sharing his pages, for which purpose this is provided.
  435.    *
  436.    * @param perm The integer permission, 9 bits of this value are used.
  437.    */
  438.   static void set_permission(int);
  439.   /**
  440.    * If the user wants to allocate shared memory to use with
  441.    * his programs, he should use the following methods to accomplish
  442.    * this means.  These methods will provide for management of
  443.    * the memory pages, and ensure their destruction on
  444.    * program exit.
  445.    *
  446.    * Allocate memory, with a given size and return a pointer
  447.    * to it, or 0 if no memory is available for sharing.
  448.    *
  449.    * @param s The size of the wanted memory block.
  450.    * @return A pointer to allocated memory, or 0 on error.
  451.    */
  452.   static void *shalloc(size_t);
  453.   /**
  454.    * Dealloc a memory block that was allocated with the above
  455.    * method.
  456.    *
  457.    * Note, that this routine will collect fragmented memory
  458.    * into a whole segment if possible and upon receiving
  459.    * a whole segment that has been reed, it will return it
  460.    * back to the system and destroy its reference id.
  461.    *
  462.    * @param p The pointer return by the above method.
  463.    */
  464.   static void shdealloc(void *);
  465.   pthread& operator= (cancel_state s) { this->set(s); return (*this); };
  466.   pthread& operator= (cancel_type t)  { this->set(t); return (*this); };
  467. };
  468. #endif