thread.h
上传用户:shtangtang
上传日期:2007-01-04
资源大小:167k
文件大小:16k
- /***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
- /**
- * Copyright (c) 1999
- *
- * A C++ implementation of posix threads, using Linux clone system
- * calls.
- *
- * The implementation is identical to the implementation found in
- * the linuxthreads package, except that each thread is an object
- * here.
- *
- * Using Linux pthread package, has a rather bad
- * bi-effect in C++. When a routine, is called
- * inside a class, it looses it's scope on the
- * class. That is, the 'this' pointer. This
- * superclass is to remedy that.
- *
- * @author Orn Hansen <oe.hansen@gamma.telenordia.se>
- * @short a C++ implementation of threads for linux.
- */
- #ifndef __THREADS_LIBRARY_H
- #define __THREADS_LIBRARY_H
- #define _THREAD_SAFE
- #define DEFAULTMUTEX mutex_t()
- class mutex;
- class cond;
- class spinlock;
- typedef mutex mutex_t;
- typedef cond cond_t;
- typedef spinlock spinlock_t;
- #define mutex_lock(x) ((mutex_t *)x)->lock()
- #define mutex_unlock(x) ((mutex_t *)x)->unlock()
- #include <thread_alloc.h>
- #include <thread_mutex.h>
- #include <thread_cond.h>
- #include <thread_semaphore.h>
- extern "C" {
- # include <setjmp.h>
- # include <unistd.h>
- };
- #ifndef PTHREAD_CANCELED
- #define PTHREAD_CANCELED ((void *)-1)
- #endif
- #define PTHREAD_SIG_RESTART s_user1
- #define PTHREAD_SIG_CANCEL s_user2
- /**
- * Threads, are cloned processes that share the same
- * memory for reading and writing. This is a primitive
- * and needs to be a superclass to any specific needs for
- * threaded execution.
- *
- * @short Abstract class for threads.
- * @author Orn Hansen <oe.hansen@gamma.telenordia.se>
- */
- class pthread {
- public:
- enum cancel_state {
- cancel_enable,
- cancel_disable
- };
- enum cancel_type {
- cancel_deferred,
- cancel_asynchronous
- };
- enum jumps {
- signal_jmp,
- cancel_jmp
- };
- enum booleans {
- set_terminated,
- set_detached,
- set_exited,
- set_canceled,
- set_private
- };
- private:
- int p_id;
- char* p_sp;
- spinlock p_spinlock;
- attributes p_attributes;
- int p_priority;
- int p_signal;
- int p_joining;
- int p_errno;
- void* p_retval;
- int p_retcode;
- sigjmp_buf* p_signal_jmp;
- sigjmp_buf* p_cancel_jmp;
- bool p_terminated;
- bool p_exited;
- cancel_state p_cancelstate;
- cancel_type p_canceltype;
- bool p_canceled;
- void varinit();
- void invoke(void *);
- bool error(int val) { p_errno = val; return false; };
- public:
- pthread();
- pthread(void *);
- pthread(int);
- virtual ~pthread();
- /**
- * An abstract definition of the method, that will be run
- * as a different process by this class. This is the starting
- * point, of the new process.
- *
- * In creating a new process, it should be taken care off that
- * the process itself, is starting its execution at the same
- * time as the construction is initializing class variables. This
- * may be unwanted, and to have a process wait for the initialization
- * to finish, the following method can be used.
- *
- * <pre>
- *
- * #include <thread.h>
- *
- * class mythread : public pthread {
- * private:
- * semaphore run_away;
- * string something;
- *
- * public:
- * mythread()
- * {
- * something = "This has been initialized";
- * run_away.post(); // last instruction in constructor.
- * }
- * ~mythread()
- * {
- * // TODO: destroy variables.
- * }
- *
- * int thread(void *)
- * {
- * run_away.wait();
- * // Now, the process is synchronized to run after
- * // the initialisation has finished.
- * }
- * };
- *
- * </pre>
- *
- * The above mechanism, can both be seen as a quirk, and as a drawback.
- * In most cases, the thread doesn't need the variables in its class,
- * so forcing the thread to wait until the constructor has finished
- * isn't necessary... and perhaps even unwanted.
- *
- * @param any The process will receive a parameter, whose type is only known internally.
- * @return Actually, nothing is returned here. See @ref #retval how to acquire return values.
- */
- virtual int thread(void *) = 0;
- /**
- * This method allows access to the value returned by the process, if
- * it has returned, that is. Otherwise, it contains an undefined value.
- *
- * @return A pointer, that the thread can register as a return value.
- */
- void *retval() const { return p_retval; };
- /**
- * This method defines, wether the thread is joining with another
- * thread. The return value, is either the process id of the
- * thread that is to be joined with, or 0 which indicates that
- * it is not being joined with anyone.
- *
- * @return the pid of the process to join with.
- */
- int joining() const { return p_joining; };
- /**
- * If an error has occurred, during the process, it will be locally
- * stored and can be retrieved by this method. Note however, that
- * it is upon the user to make sure that his thread sets this value
- * with the @ref #error function.
- *
- * @return The last errorvalue registered.
- */
- int gerrno() const { return p_errno; };
- /**
- * Each thread has its own process id, and even though it is
- * possible with the clone system to clone the process id as well,
- * it is not done within this thread package.
- *
- * @return the pid of this thread.
- */
- int id() const { return p_id; };
- /**
- * Each time a thread receives a signal, it stores the
- * signal number locally so that parent threads can view
- * or debug its status.
- *
- * @return Last signal received by the thread.
- */
- int signal() const { return p_signal; };
- /**
- * This is a convenience function, provided to simplify the
- * use of sending signals to a thread. If the user has access to
- * the thread class, he can use this method to signal the thread
- * instead of the system kill function.
- *
- * @return Last signal received by the thread.
- */
- int signal(int);
- /**
- * A running thread can terminate in several ways, it can
- * terminate by returning or exiting from the thread, or it
- * can be canceled from inside or from an outside source.
- * This function reports if the thread was canceled.
- *
- * @return True if the thread has been canceled.
- */
- bool canceled() const { return p_canceled; };
- /**
- * Usually all threads created by the main program will be
- * hanging on to it. This means, that when the main program
- * stops execution, the thread belonging to it will be
- * terminated when it exits. The thread can however detach
- * itself from the main thread.
- *
- * @return True if the thread has been detached.
- */
- bool detached() const;
- /**
- * A detached thread, isn't joinable... there may also be
- * other situations where a thread does not want a parent
- * thread to join onto it.
- *
- * @return True if the thread can be joined with.
- */
- bool joinable() const;
- /**
- * If a thread has terminated its run, this status will
- * be stored for parent threads to examine.
- *
- * @return True if the thread has terminated its running loop.
- */
- bool terminated() const { return p_terminated; };
- /**
- * There are several ways, as previously mentioned, for a thread
- * to finish. One way, is that it uses the 'exit()' call belonging
- * to the class, another that it simply 'returns' from the
- * loop.
- *
- * @return True, if the thread has exited with 'exit'.
- */
- bool exited() const { return p_exited; };
- /**
- * Return the cancel state of the process. The process
- * can disable cancelation, which will make it useful to
- * be able to check if it is actually possible to cancel
- * it. The cancel state can be one of:
- *
- * <pre>
- * cancel_enable - The process can be cancelled.
- * cancel_disable - The process cannot be cancelled.
- * </pre>
- *
- * @return The cancel state.
- */
- cancel_state cancelstate() const { return p_cancelstate; };
- /**
- * If cancels occur, the process can treat them in one of
- * two ways. It can be handled asynchronously, or it can
- * deferred. Cancel type, is thus one of:
- *
- * <pre>
- * cancel_deferred - Cancels are deferred.
- * cancel_asynchronous - Asynchronous cancels.
- * </pre>
- *
- * @return the cancel type.
- */
- cancel_type canceltype() const { return p_canceltype; };
- /**
- * Join this thread, with another thread. When this
- * thread terminates, the joined process will be signalled
- * to revive it from a slumber, as a result.
- *
- * @param pid The pid of the process to revive on exit.
- * @return The pid that was set.
- */
- int joining(int s) { return p_joining = s; };
- /**
- * Set the cancelation state for this thread, see
- * @ref #cancelstate for a discussion on the states available.
- */
- void set(cancel_state s) { p_cancelstate = s; };
- /**
- * Set the cancelation type for this thread, see
- * @ref #canceltype for a discussion on the types that
- * are available.
- */
- void set(cancel_type t) { p_canceltype = t; };
- /**
- * Set the points to jump to, on cancel or signal signals. The
- * jump types are:
- *
- * <pre>
- * cancel_jmp - When a cancel signal occurs.
- * signal_jmp - On a normal signal.
- * </pre>
- *
- * @param jump the jump kind, as above.
- * @param sigjmp The jump point to set.
- */
- void set(jumps, sigjmp_buf *);
- /**
- * Set any of the boolean variables this thread contains. The
- * following are for use:
- *
- * <pre>
- * set_canceled - Signify cancel state.
- * set_terminated - Signify termination state.
- * set_detached - Signify detached state.
- * set_exited - Signify exited state.
- * </pre>
- *
- * The state can only be set, by the process owner. In this case,
- * the thread itself.
- * @param type The type, as above.
- * @param bool A boolean value, to set to.
- */
- void set(booleans, bool);
- /**
- * Cancel the process. This will halt the threads execution,
- * set the cancel state to cancel. If the cancel type is
- * asynchronous, it will also exit the main loop with an exit
- * value of -1, else if the cancel type is deferred it will
- * jump to a location specified.
- */
- void cancel();
- /**
- * Suspend the process. The process is halted, but not
- * terminated... a suspended process cannot be cancelled,
- * unless it has been suspended with that in mind
- * see @ref #suspend_with_cancellation
- * The process will be restarted, upon receiving a restart
- * signal see @ref #restart
- */
- static void suspend();
- /**
- * suspend the calling process, until it is cancelled or
- * receives a signal. This does the same thing as @ref #suspend
- * but unlike it, the thread can be cancelled when waiting
- * for a signal inside this function.
- */
- static void suspend_with_cancelation();
- /**
- * restart the thread, associated with the class instance. This
- * will in effect send a SIGUSR1 signal to the process, which will
- * wake it up, if it is in a suspended state or otherwise won't
- * do a thing.
- */
- void restart();
- /**
- * Jump to a given location, look at @ref #set for a discussion on
- * how to set the location to jump to.
- */
- void jump(jumps);
- /**
- * exit the process, with a given return value. This will only
- * work if the calling process is the same as the thread running
- * inside the class instance. Calling this function from a
- * parent thread, will not have any effect on this class's thread
- * but rather on the calling thread.
- */
- void exit(void *);
- /**
- * exit the process as above, but give a retcode as a result
- * insteaad of a pointer to a return value.
- */
- void exit(int);
- /**
- * exit the process as above, but give the normal zero return
- * value.
- */
- void exit() { this->exit(0); };
- /**
- * If a thread exits with 'return val' from inside the thread
- * function, the return value will be stored and retreivable
- * through this function.
- *
- * @return The return value of the thread.
- */
- int retcode();
- /**
- * Tell if the process of the thread instance is running. This
- * function is really not very useful, it calls the scheduler
- * to see if it has the thread scheduled. Which the scheduler
- * does, even if the thread is a zombie. See @ref #terminated
- * and @ref #cancelled for different methods in determining
- * wether the thread is still alive.
- */
- bool running();
- /**
- * Join the calling process, with the thread instance. This
- * will suspend the calling process, until the thread has
- * terminated. The call can return one of the following
- * error values:
- *
- * <pre>
- * EDLCK - Dead lock would occur.
- * ESRCH - The process is not in the list.
- * EINVAL - The thread is detached, or already joining another.
- * 0 - The thread has terminated.
- * </pre>
- * @return err A value, as seen above.
- */
- int join();
- /**
- * In a shared environment, each process must have it's system wide
- * project name that uniquely identifies it and enables other
- * processes to identify its resources for sharing. This method is
- * provided to change the current project identity to your hearts
- * desire.
- *
- * Note: these project id's will be created as filenames inside
- * the tmp directory, during the process run. This is done because
- * the shared memory key scheme want's an inode number for use in
- * shared memory key creation.
- *
- * @param str A C string, giving the name of a common project.
- */
- static void set_project(const char *);
- /**
- * In creating a project, the default permission scheme used is
- * RW-R--R-- i.e. Read Write for the user, and Read permission for
- * everyone else. The user however, may want a different scheme
- * in sharing his pages, for which purpose this is provided.
- *
- * @param perm The integer permission, 9 bits of this value are used.
- */
- static void set_permission(int);
- /**
- * If the user wants to allocate shared memory to use with
- * his programs, he should use the following methods to accomplish
- * this means. These methods will provide for management of
- * the memory pages, and ensure their destruction on
- * program exit.
- *
- * Allocate memory, with a given size and return a pointer
- * to it, or 0 if no memory is available for sharing.
- *
- * @param s The size of the wanted memory block.
- * @return A pointer to allocated memory, or 0 on error.
- */
- static void *shalloc(size_t);
- /**
- * Dealloc a memory block that was allocated with the above
- * method.
- *
- * Note, that this routine will collect fragmented memory
- * into a whole segment if possible and upon receiving
- * a whole segment that has been reed, it will return it
- * back to the system and destroy its reference id.
- *
- * @param p The pointer return by the above method.
- */
- static void shdealloc(void *);
- pthread& operator= (cancel_state s) { this->set(s); return (*this); };
- pthread& operator= (cancel_type t) { this->set(t); return (*this); };
- };
- #endif