diff options
Diffstat (limited to 'kviewshell/plugins/djvu/libdjvu/GThreads.h')
-rw-r--r-- | kviewshell/plugins/djvu/libdjvu/GThreads.h | 639 |
1 files changed, 639 insertions, 0 deletions
diff --git a/kviewshell/plugins/djvu/libdjvu/GThreads.h b/kviewshell/plugins/djvu/libdjvu/GThreads.h new file mode 100644 index 00000000..92691db4 --- /dev/null +++ b/kviewshell/plugins/djvu/libdjvu/GThreads.h @@ -0,0 +1,639 @@ +//C- -*- C++ -*- +//C- ------------------------------------------------------------------- +//C- DjVuLibre-3.5 +//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun. +//C- Copyright (c) 2001 AT&T +//C- +//C- This software is subject to, and may be distributed under, the +//C- GNU General Public License, Version 2. The license should have +//C- accompanied the software or you may obtain a copy of the license +//C- from the Free Software Foundation at http://www.fsf.org . +//C- +//C- This program is distributed in the hope that it will be useful, +//C- but WITHOUT ANY WARRANTY; without even the implied warranty of +//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//C- GNU General Public License for more details. +//C- +//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library +//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech +//C- Software authorized us to replace the original DjVu(r) Reference +//C- Library notice by the following text (see doc/lizard2002.djvu): +//C- +//C- ------------------------------------------------------------------ +//C- | DjVu (r) Reference Library (v. 3.5) +//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved. +//C- | The DjVu Reference Library is protected by U.S. Pat. No. +//C- | 6,058,214 and patents pending. +//C- | +//C- | This software is subject to, and may be distributed under, the +//C- | GNU General Public License, Version 2. The license should have +//C- | accompanied the software or you may obtain a copy of the license +//C- | from the Free Software Foundation at http://www.fsf.org . +//C- | +//C- | The computer code originally released by LizardTech under this +//C- | license and unmodified by other parties is deemed "the LIZARDTECH +//C- | ORIGINAL CODE." Subject to any third party intellectual property +//C- | claims, LizardTech grants recipient a worldwide, royalty-free, +//C- | non-exclusive license to make, use, sell, or otherwise dispose of +//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the +//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU +//C- | General Public License. This grant only confers the right to +//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to +//C- | the extent such infringement is reasonably necessary to enable +//C- | recipient to make, have made, practice, sell, or otherwise dispose +//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to +//C- | any greater extent that may be necessary to utilize further +//C- | modifications or combinations. +//C- | +//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY +//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF +//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +//C- +------------------------------------------------------------------ +// +// $Id: GThreads.h,v 1.10 2003/11/07 22:08:21 leonb Exp $ +// $Name: release_3_5_15 $ + +#ifndef _GTHREADS_H_ +#define _GTHREADS_H_ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#if NEED_GNUG_PRAGMAS +# pragma interface +#endif + + +/** @name GThreads.h + + Files #"GThreads.h"# and #"GThreads.cpp"# implement common entry points + for multithreading on multiple platforms. Each execution thread is + represented by an instance of class \Ref{GThread}. Synchronization is + provided by class \Ref{GMonitor} which implements a monitor (C.A.R Hoare, + Communications of the ACM, 17(10), 1974). + + The value of compiler symbol #THREADMODEL# selects an appropriate + implementation for these classes. The current implementation supports + the following values: + \begin{description} + \item[-DTHREADMODEL=NOTHREADS] Dummy implementation. This is a + good choice when the multithreading features are not required, + because it minimizes the portability problems. This is currently + the default when compiling under Unix. + \item[-DTHREADMODEL=WINTHREADS] Windows implementation. + This is the default when compiling under Windows. + \item[-DTHREADMODEL=MACTHREADS] Macintosh implementation, + which is based on the MacOS cooperative model. The current + implementation does not yet fully support synchronization. + This is the default when compiling under MacOS. + \item[-DTHREADMODEL=POSIXTHREADS] Posix implementation. + This implementation also supports DCE threads. The behavior of + the code is subject to the quality of the system implementation of + Posix threads. + \item[-DTHREADMODEL=COTHREADS] Custom cooperative threads. + These custom threads do not redefine system calls. Before executing + a potentially blocking system function, each thread must explicitly + check whether it is going to block and yield control explicitly if + this is the case. This code must be compiled with a patched version + of egcs-1.1.1 \URL{http://egcs.cygnus.com}. The patch addresses + exception thread-safety and is provided in #"@Tools/libgcc2.c.diff"#. + Once you get the right compiler, this implementation is remarkably + compact and portable. A variety of processors are supported, + including mips, intel, sparc, hppa, and alpha. + \item[-DTHREADMODEL=JRITHREADS] Java implementation hooks. + Multi-threading within a Netscape plugin can be tricky. A simple + idea however consists of implementing the threading primitives in + Java and to access them using JRI. The classes just contain a + JRIGlobalRef. This is not a real implementation since everything + (Java code, native functions, stubs, exception thread safety) must + be addressed by the plugin source code. Performance may be a serious + issue. + \end{description} + + {\bf Portability}: The simultaneous use of threads and exceptions caused a + lot of portability headaches under Unix. We eventually decided to + implement the COTHREADS cooperative threads (because preemptive threads + have more problems) and to patch EGCS in order to make exception handling + COTHREAD-safe. + + @memo + Portable threads + @author + L\'eon Bottou <leonb@research.att.com> -- initial implementation.\\ + Praveen Guduru <praveen@sanskrit.lz.att.com> -- mac implementation. + +// From: Leon Bottou, 1/31/2002 +// Almost unchanged by Lizardtech. +// GSafeFlags should go because it not as safe as it claims. + + @version + #$Id: GThreads.h,v 1.10 2003/11/07 22:08:21 leonb Exp $# */ +//@{ + + +#include "DjVuGlobal.h" +#include "GException.h" + +#define NOTHREADS 0 +#define COTHREADS 1 +#define JRITHREADS 2 +#define POSIXTHREADS 10 +#define WINTHREADS 11 +#define MACTHREADS 12 + +// Known platforms +#ifndef THREADMODEL +#if defined(WIN32) +#define THREADMODEL WINTHREADS +#endif +#if defined(macintosh) +#define THREADMODEL MACTHREADS +#endif +#endif + +// Exception emulation is not thread safe +#ifdef USE_EXCEPTION_EMULATION +#undef THREADMODEL +#define THREADMODEL NOTHREADS +#endif +// Default is nothreads +#ifndef THREADMODEL +#define THREADMODEL NOTHREADS +#endif + +// ---------------------------------------- +// INCLUDES + +#if THREADMODEL==WINTHREADS +#ifndef _WINDOWS_ +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#endif +#endif + +#if THREADMODEL==MACTHREADS +#include <threads.h> +#endif + +#if THREADMODEL==POSIXTHREADS +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#undef TRY +#undef CATCH +#define _CMA_NOWRAPPERS_ +#include <pthread.h> +#endif + +#if THREADMODEL==JRITHREADS +#include "jri.h" +#endif + +#if THREADMODEL==COTHREADS +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#endif + + +// ---------------------------------------- +// PORTABLE CLASSES + + +#ifdef HAVE_NAMESPACES +namespace DJVU { +# ifdef NOT_DEFINED // Just to fool emacs c++ mode +} +#endif +#endif + + + +/** Thread class. A multithreaded process is composed of a main execution + thread and of several secondary threads. Each secondary thread is + represented by a #GThread# object. The amount of memory required for the + stack of a secondary thread is defined when the #GThread# object is + constructed. The execution thread is started when function + \Ref{GThread::create} is called. The destructor of class GThread waits + until the thread terminanes. Note that the execution can be terminated at + any time (with possible prejudice) by calling \Ref{GThread::terminate}. + + Several static member functions control the thread scheduler. Function + \Ref{GThread::yield} relinquishes the processor to another thread. + Function \Ref{GThread::select} (#COTHREADS# only) provides a thread-aware + replacement for the well-known unix system call #select#. + + {\bf Note} --- Both the copy constructor and the copy operator are declared + as private members. It is therefore not possible to make multiple copies + of instances of this class, as implied by the class semantic. */ + +class GThread { +public: + /** Constructs a new thread object. Memory is allocated for the + thread, but the thread is not started. + Argument #stacksize# is used by the #COTHREADS# model only for + specifying the amount of memory needed for the processor stack. A + negative value will be replaced by a suitable default value of 128Kb. + A minimum value of 32Kb is silently enforced. */ + GThread(int stacksize = -1); + /** Destructor. Destroying the thread object while the thread is running is + perfectly ok since it only destroys the thread identifier. Execution + will continue without interference. */ + ~GThread(); + /** Starts the thread. The new thread executes function #entry# with + argument #arg#. The thread terminates when the function returns. A + thread cannot be restarted after its termination. You must create a new + #GThread# object. */ + int create(void (*entry)(void*), void *arg); + /** Terminates a thread with extreme prejudice. The thread is removed from + the scheduling list. Execution terminates regardless of the execution + status of the thread function. Automatic variables may or may not be + destroyed. This function must be considered as a last resort since + memory may be lost. */ + void terminate(); + /** Causes the current thread to relinquish the processor. The scheduler + selects a thread ready to run and transfers control to that thread. The + actual effect of #yield# heavily depends on the selected implementation. + Function #yield# usually returns zero when the execution of the current + thread is resumed. It may return a positive number when it can + determine that the current thread will remain the only runnable thread + for some time. You may then call function \Ref{get_select} to + obtain more information. */ + static int yield(); + /** Returns a value which uniquely identifies the current thread. */ + static void *current(); + +#if THREADMODEL==WINTHREADS +private: + HANDLE hthr; + DWORD thrid; +#elif THREADMODEL==MACTHREADS +private: + unsigned long thid; + static pascal void *start(void *arg); +#elif THREADMODEL==POSIXTHREADS +private: + pthread_t hthr; + static void *start(void *arg); +#elif THREADMODEL==JRITHREADS +private: + JRIGlobalRef obj; +#elif THREADMODEL==COTHREADS + friend class GMonitor; +public: + class cotask; + class cotask *task; + /** Replaces system call #select# (COTHREADS only). The #COTHREADS# model + does not redefine system function. System functions therefore can + potentially block the whole process (instead of blocking the current + thread only) because the system is not aware of the #COTHREADS# + scheduler. The function #GThread::select# is a #COTHREADS#-aware + replacement for the well known system function #select#. You can also + use #GThread::select# for making sure that calls to system functions + will not block the entire process, as demonstrated below: + \begin{verbatim} + int + gthread_read(int fd, void *buffer, size_t len) + { + fd_set rdset; + FD_ZERO(&rdset); + FD_SET(fd, &rdset); + GThread::select(fd+1, &rdset, 0, 0, 0); + return read(fd, buffer, len); + } + \end{verbatim} */ + static int select(int nfds, fd_set*, fd_set*, fd_set*, struct timeval*); + /** Provide arguments for system call #select# (COTHREADS only). It may be + appropriate to call the real system call #select# if the current thread + is the only thread ready to run. Other threads however may wake up when + certain file descriptors are ready or when a certain delay expires. + Function #get_select# returns this information by filling the three + usual file descriptor sets (similar to the arguments of system call + #select#). It also returns a timeout #timeout# expressed in + milliseconds. Note that this timeout is zero is the current thread is + not the sole thread ready to run. */ + static void get_select(int &nfds, fd_set*, fd_set*, fd_set*, unsigned long &timeout); + /** Install hooks in the scheduler (COTHREADS only). The hook function + #call# is called when a new thread is created (argument is + #GThread::CallbackCreate#), when a thread terminates (argument is + #GThread::CallbackTerminate#), or when thread is unblocked (argument is + #GThread::CallbackUnblock#). This callback can be useful in certain GUI + toolkits where the most convenient method for scheduling the threads + consists in setting a timer event that calls \Ref{GThread::yield}. */ + static void set_scheduling_callback(void (*call)(int)); + enum { CallbackCreate, CallbackTerminate, CallbackUnblock }; + +#endif +public: + // Should be considered as private + void (*xentry)(void*); + void *xarg; +private: + // Disable default members + GThread(const GThread&); + GThread& operator=(const GThread&); +}; + + +/** Monitor class. Monitors have been first described in (C.A.R Hoare, + Communications of the ACM, 17(10), 1974). This mechanism provides the + basic mutual exclusion (mutex) and thread notification facilities + (condition variables). + + Only one thread can own the monitor at a given time. Functions + \Ref{enter} and \Ref{leave} can be used to acquire and release the + monitor. This mutual exclusion provides an efficient way to protect + segment of codes ({\em critical sections}) which should not be + simultaneously executed by two threads. Class \Ref{GMonitorLock} provides + a convenient way to do this effectively. + + When the thread owning the monitor calls function \Ref{wait}, the monitor + is released and the thread starts waiting until another thread calls + function \Ref{signal} or \Ref{broadcast}. When the thread wakes-up, it + re-acquires the monitor and function #wait# returns. Since the signaling + thread must acquire the monitor before calling functions #signal# and + #broadcast#, the signaled thread will not be able to re-acquire the + monitor until the signaling thread(s) releases the monitor. + + {\bf Note} --- Both the copy constructor and the copy operator are declared + as private members. It is therefore not possible to make multiple copies + of instances of this class, as implied by the class semantic. */ + +class GMonitor +{ +public: + GMonitor(); + ~GMonitor(); + /** Enters the monitor. If the monitor is acquired by another thread this + function waits until the monitor is released. The current thread then + acquires the monitor. Calls to #enter# and #leave# may be nested. */ + void enter(); + /** Leaves the monitor. The monitor counts how many times the current + thread has entered the monitor. Function #leave# decrement this count. + The monitor is released when this count reaches zero. An exception is + thrown if this function is called by a thread which does not own the + monitor. */ + void leave(); + /** Waits until the monitor is signaled. The current thread atomically + releases the monitor and waits until another thread calls function + #signal# or #broadcast#. Function #wait# then re-acquires the monitor + and returns. An exception is thrown if this function is called by a + thread which does not own the monitor. */ + void wait(); + /** Waits until the monitor is signaled or a timeout is reached. The + current thread atomically releases the monitor and waits until another + thread calls function #signal# or #broadcast# or a maximum of #timeout# + milliseconds. Function #wait# then re-acquires the monitor and returns. + An exception is thrown if this function is called by a thread which does + not own the monitor. */ + void wait(unsigned long timeout); + /** Signals one waiting thread. Function #signal# wakes up at most one of + the waiting threads for this monitor. An exception is thrown if this + function is called by a thread which does not own the monitor. */ + void signal(); + /** Signals all waiting threads. Function #broadcast# wakes up all the + waiting threads for this monitor. An exception is thrown if this + function is called by a thread which does not own the monitor. */ + void broadcast(); +private: +#if THREADMODEL==WINTHREADS + int ok; + int count; + DWORD locker; + CRITICAL_SECTION cs; + struct thr_waiting *head; + struct thr_waiting *tail; +#elif THREADMODEL==MACTHREADS + int ok; + int count; + unsigned long locker; + int wlock; + int wsig; +#elif THREADMODEL==POSIXTHREADS + int ok; + int count; + pthread_t locker; + pthread_mutex_t mutex; + pthread_cond_t cond; +#elif THREADMODEL==COTHREADS + int ok; + int count; + void *locker; + int wlock; + int wsig; +#elif THREADMODEL==JRITHREADS + JRIGlobalRef obj; +#endif +private: + // Disable default members + GMonitor(const GMonitor&); + GMonitor& operator=(const GMonitor&); +}; + + + + +// ---------------------------------------- +// NOTHREADS INLINES + +#if THREADMODEL==NOTHREADS +inline GThread::GThread(int) {} +inline GThread::~GThread(void) {} +inline void GThread::terminate() {} +inline int GThread::yield() { return 0; } +inline void* GThread::current() { return 0; } +inline GMonitor::GMonitor() {} +inline GMonitor::~GMonitor() {} +inline void GMonitor::enter() {} +inline void GMonitor::leave() {} +inline void GMonitor::wait() {} +inline void GMonitor::wait(unsigned long) {} +inline void GMonitor::signal() {} +inline void GMonitor::broadcast() {} +#endif // NOTHREADS + + +// ---------------------------------------- +// SCOPE LOCK + + +/** Wrapper for mutually exclusive code. + This class locks a specified critical section (see \Ref{GCriticalSection}) + at construction time and unlocks it at destruction time. It provides a + convenient way to take advantage of the C++ implicit destruction of + automatic variables in order to make sure that the monitor is + released when exiting the protected code. The following code will release + the monitor when the execution thread leaves the protected scope, either + because the protected code has executed successfully, or because an + exception was thrown. + \begin{verbatim} + { -- protected scope + static GMonitor theMonitor; + GMonitorLock lock(&theMonitor) + ... -- protected code + } + \end{verbatim} + This construct will do nothing when passed a null pointer. +*/ +class GMonitorLock +{ +private: + GMonitor *gsec; +public: + /** Constructor. Enters the monitor #gsec#. */ + GMonitorLock(GMonitor *gsec) : gsec(gsec) + { if (gsec) gsec->enter(); }; + /** Destructor. Leaves the associated monitor. */ + ~GMonitorLock() + { if (gsec) gsec->leave(); }; +}; + + + +// ---------------------------------------- +// GSAFEFLAGS (not so safe) + + +/** A thread safe class representing a set of flags. The flags are protected + by \Ref{GMonitor}, which is attempted to be locked whenever somebody + accesses the flags. One can modify the class contents using one of + two functions: \Ref{test_and_modify}() and \Ref{wait_and_modify}(). + Both of them provide atomic operation of testing (first) and modification + (second). The flags remain locked between the moment of testing and + modification, which guarantees, that their state cannot be changed in + between of these operations. */ +class GSafeFlags : public GMonitor +{ +private: + volatile long flags; +public: + /// Constructs #GSafeFlags# object. + GSafeFlags(long flags=0); + + /** Assignment operator. Will also wake up threads waiting for the + flags to change. */ + GSafeFlags & operator=(long flags); + + /** Returns the value of the flags */ + operator long(void) const; + /** Modifies the flags by ORing them with the provided mask. A broadcast + will be sent after the modification is done. */ + GSafeFlags & operator|=(long mask); + /** Modifies the flags by ANDing them with the provided mask. A broadcast + will be sent after the modification is done. */ + GSafeFlags & operator&=(long mask); + + /** If all bits mentioned in #set_mask# are set in the flags and all + bits mentioned in #clr_mask# are cleared in the flags, it sets all + bits from #set_mask1# in the flags, clears all flags from + #clr_mask1# in the flags and returns #TRUE#. Otherwise returns + #FALSE#. */ + bool test_and_modify(long set_mask, long clr_mask, + long set_mask1, long clr_mask1); + + /** Waits until all bits mentioned in #set_mask# are set in the flags + and all bits mentioned in #clr_flags# are cleared in the flags. + After that it sets bits from #set_mask1# and clears bits from + #clr_mask1# in the flags. */ + void wait_and_modify(long set_mask, long clr_mask, + long set_mask1, long clr_mask1); + + /** Waits until all bits set in #set_mask# are set in the flags and + all bits mentioned in #clr_mask# are cleared in the flags. */ + void wait_for_flags(long set_mask, long clr_mask=0) const; + + /** Modifies the flags by setting all bits mentioned in #set_mask# + and clearing all bits mentioned in #clr_mask#. If the flags have + actually been modified, a broadcast will be sent. */ + void modify(long set_mask, long clr_mask); +}; + +inline +GSafeFlags::GSafeFlags(long xflags) + : flags(xflags) +{ +} + +inline void +GSafeFlags::wait_for_flags(long set_mask, long clr_mask) const +{ + ((GSafeFlags *) this)->wait_and_modify(set_mask, clr_mask, 0, 0); +} + +inline void +GSafeFlags::modify(long set_mask, long clr_mask) +{ + test_and_modify(0, 0, set_mask, clr_mask); +} + +inline GSafeFlags & +GSafeFlags::operator|=(long mask) +{ + test_and_modify(0, 0, mask, 0); + return *this; +} + +inline GSafeFlags & +GSafeFlags::operator&=(long mask) +{ + test_and_modify(0, 0, 0, ~mask); + return *this; +} + +//@} + + + + +// ---------------------------------------- +// COMPATIBILITY CLASSES + + +// -- these classes are no longer documented. + +class GCriticalSection : protected GMonitor +{ +public: + void lock() + { GMonitor::enter(); }; + void unlock() + { GMonitor::leave(); }; +}; + +class GEvent : protected GMonitor +{ +private: + int status; +public: + GEvent() + : status(0) { }; + void set() + { if (!status) { enter(); status=1; signal(); leave(); } }; + void wait() + { enter(); if (!status) GMonitor::wait(); status=0; leave(); }; + void wait(int timeout) + { enter(); if (!status) GMonitor::wait(timeout); status=0; leave(); }; +}; + +class GCriticalSectionLock +{ +private: + GCriticalSection *gsec; +public: + GCriticalSectionLock(GCriticalSection *gsec) : gsec(gsec) + { if (gsec) gsec->lock(); }; + ~GCriticalSectionLock() + { if (gsec) gsec->unlock(); }; +}; + + +// ---------------------------------------- + +#ifdef HAVE_NAMESPACES +} +# ifndef NOT_USING_DJVU_NAMESPACE +using namespace DJVU; +# endif +#endif +#endif //_GTHREADS_H_ + |