|
Packit |
df99a1 |
//C- -*- C++ -*-
|
|
Packit |
df99a1 |
//C- -------------------------------------------------------------------
|
|
Packit |
df99a1 |
//C- DjVuLibre-3.5
|
|
Packit |
df99a1 |
//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun.
|
|
Packit |
df99a1 |
//C- Copyright (c) 2001 AT&T
|
|
Packit |
df99a1 |
//C-
|
|
Packit |
df99a1 |
//C- This software is subject to, and may be distributed under, the
|
|
Packit |
df99a1 |
//C- GNU General Public License, either Version 2 of the license,
|
|
Packit |
df99a1 |
//C- or (at your option) any later version. The license should have
|
|
Packit |
df99a1 |
//C- accompanied the software or you may obtain a copy of the license
|
|
Packit |
df99a1 |
//C- from the Free Software Foundation at http://www.fsf.org .
|
|
Packit |
df99a1 |
//C-
|
|
Packit |
df99a1 |
//C- This program is distributed in the hope that it will be useful,
|
|
Packit |
df99a1 |
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
df99a1 |
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
df99a1 |
//C- GNU General Public License for more details.
|
|
Packit |
df99a1 |
//C-
|
|
Packit |
df99a1 |
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
|
|
Packit |
df99a1 |
//C- Lizardtech Software. Lizardtech Software has authorized us to
|
|
Packit |
df99a1 |
//C- replace the original DjVu(r) Reference Library notice by the following
|
|
Packit |
df99a1 |
//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
|
|
Packit |
df99a1 |
//C-
|
|
Packit |
df99a1 |
//C- ------------------------------------------------------------------
|
|
Packit |
df99a1 |
//C- | DjVu (r) Reference Library (v. 3.5)
|
|
Packit |
df99a1 |
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
|
|
Packit |
df99a1 |
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
|
|
Packit |
df99a1 |
//C- | 6,058,214 and patents pending.
|
|
Packit |
df99a1 |
//C- |
|
|
Packit |
df99a1 |
//C- | This software is subject to, and may be distributed under, the
|
|
Packit |
df99a1 |
//C- | GNU General Public License, either Version 2 of the license,
|
|
Packit |
df99a1 |
//C- | or (at your option) any later version. The license should have
|
|
Packit |
df99a1 |
//C- | accompanied the software or you may obtain a copy of the license
|
|
Packit |
df99a1 |
//C- | from the Free Software Foundation at http://www.fsf.org .
|
|
Packit |
df99a1 |
//C- |
|
|
Packit |
df99a1 |
//C- | The computer code originally released by LizardTech under this
|
|
Packit |
df99a1 |
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
|
|
Packit |
df99a1 |
//C- | ORIGINAL CODE." Subject to any third party intellectual property
|
|
Packit |
df99a1 |
//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
|
|
Packit |
df99a1 |
//C- | non-exclusive license to make, use, sell, or otherwise dispose of
|
|
Packit |
df99a1 |
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
|
|
Packit |
df99a1 |
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
|
|
Packit |
df99a1 |
//C- | General Public License. This grant only confers the right to
|
|
Packit |
df99a1 |
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
|
|
Packit |
df99a1 |
//C- | the extent such infringement is reasonably necessary to enable
|
|
Packit |
df99a1 |
//C- | recipient to make, have made, practice, sell, or otherwise dispose
|
|
Packit |
df99a1 |
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
|
|
Packit |
df99a1 |
//C- | any greater extent that may be necessary to utilize further
|
|
Packit |
df99a1 |
//C- | modifications or combinations.
|
|
Packit |
df99a1 |
//C- |
|
|
Packit |
df99a1 |
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
|
|
Packit |
df99a1 |
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
Packit |
df99a1 |
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
|
|
Packit |
df99a1 |
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
df99a1 |
//C- +------------------------------------------------------------------
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifndef _GTHREADS_H_
|
|
Packit |
df99a1 |
#define _GTHREADS_H_
|
|
Packit |
df99a1 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
df99a1 |
#include "config.h"
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
#if NEED_GNUG_PRAGMAS
|
|
Packit |
df99a1 |
# pragma interface
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** @name GThreads.h
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
Files #"GThreads.h"# and #"GThreads.cpp"# implement common entry points
|
|
Packit |
df99a1 |
for multithreading on multiple platforms. Each execution thread is
|
|
Packit |
df99a1 |
represented by an instance of class \Ref{GThread}. Synchronization is
|
|
Packit |
df99a1 |
provided by class \Ref{GMonitor} which implements a monitor (C.A.R Hoare,
|
|
Packit |
df99a1 |
Communications of the ACM, 17(10), 1974).
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
@memo
|
|
Packit |
df99a1 |
Portable threads
|
|
Packit |
df99a1 |
@author
|
|
Packit |
df99a1 |
L\'eon Bottou <leonb@research.att.com> -- initial implementation.\\
|
|
Packit |
df99a1 |
Praveen Guduru <praveen@sanskrit.lz.att.com> -- mac implementation.
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// From: Leon Bottou, 1/31/2002
|
|
Packit |
df99a1 |
// Almost unchanged by Lizardtech.
|
|
Packit |
df99a1 |
// GSafeFlags should go because it not as safe as it claims.
|
|
Packit |
df99a1 |
// Reduced to only WINTHREADS and POSIXTHREADS around djvulibre-3.5.25
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
//@{
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include "DjVuGlobal.h"
|
|
Packit |
df99a1 |
#include "GException.h"
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// Known platforms
|
|
Packit |
df99a1 |
# ifdef _WIN32
|
|
Packit |
df99a1 |
# define WINTHREADS 1
|
|
Packit |
df99a1 |
# elif HAVE_PTHREAD
|
|
Packit |
df99a1 |
# define POSIXTHREADS 1
|
|
Packit |
df99a1 |
# else
|
|
Packit |
df99a1 |
# error "Libdjvu requires thread support"
|
|
Packit |
df99a1 |
# endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// ----------------------------------------
|
|
Packit |
df99a1 |
// INCLUDES
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#if WINTHREADS
|
|
Packit |
df99a1 |
#ifndef _WINDOWS_
|
|
Packit |
df99a1 |
#define WIN32_LEAN_AND_MEAN
|
|
Packit |
df99a1 |
#include "windows.h"
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#if POSIXTHREADS
|
|
Packit |
df99a1 |
#include <sys/types.h>
|
|
Packit |
df99a1 |
#include <sys/time.h>
|
|
Packit |
df99a1 |
#include <unistd.h>
|
|
Packit |
df99a1 |
#undef TRY
|
|
Packit |
df99a1 |
#undef CATCH
|
|
Packit |
df99a1 |
#define _CMA_NOWRAPPERS_
|
|
Packit |
df99a1 |
#include <pthread.h>
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// ----------------------------------------
|
|
Packit |
df99a1 |
// PORTABLE CLASSES
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef HAVE_NAMESPACES
|
|
Packit |
df99a1 |
namespace DJVU {
|
|
Packit |
df99a1 |
# ifdef NOT_DEFINED // Just to fool emacs c++ mode
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** Thread class. A multithreaded process is composed of a main execution
|
|
Packit |
df99a1 |
thread and of several secondary threads. Each secondary thread is
|
|
Packit |
df99a1 |
represented by a #GThread# object. The amount of memory required for the
|
|
Packit |
df99a1 |
stack of a secondary thread is defined when the #GThread# object is
|
|
Packit |
df99a1 |
constructed. The execution thread is started when function
|
|
Packit |
df99a1 |
\Ref{GThread::create} is called. The destructor of class GThread waits
|
|
Packit |
df99a1 |
until the thread terminanes. Note that the execution can be terminated at
|
|
Packit |
df99a1 |
any time (with possible prejudice) by calling \Ref{GThread::terminate}.
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
Several static member functions control the thread scheduler. Function
|
|
Packit |
df99a1 |
\Ref{GThread::yield} relinquishes the processor to another thread.
|
|
Packit |
df99a1 |
Function \Ref{GThread::select} (#COTHREADS# only) provides a thread-aware
|
|
Packit |
df99a1 |
replacement for the well-known unix system call #select#.
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
{\bf Note} --- Both the copy constructor and the copy operator are declared
|
|
Packit |
df99a1 |
as private members. It is therefore not possible to make multiple copies
|
|
Packit |
df99a1 |
of instances of this class, as implied by the class semantic. */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class GThread {
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
/** Constructs a new thread object. Memory is allocated for the
|
|
Packit |
df99a1 |
thread, but the thread is not started.
|
|
Packit |
df99a1 |
Argument #stacksize# is used by the #COTHREADS# model only for
|
|
Packit |
df99a1 |
specifying the amount of memory needed for the processor stack. A
|
|
Packit |
df99a1 |
negative value will be replaced by a suitable default value of 128Kb.
|
|
Packit |
df99a1 |
A minimum value of 32Kb is silently enforced. */
|
|
Packit |
df99a1 |
GThread(int stacksize = -1);
|
|
Packit |
df99a1 |
/** Destructor. Destroying the thread object while the thread is running is
|
|
Packit |
df99a1 |
perfectly ok since it only destroys the thread identifier. Execution
|
|
Packit |
df99a1 |
will continue without interference. */
|
|
Packit |
df99a1 |
~GThread();
|
|
Packit |
df99a1 |
/** Starts the thread. The new thread executes function #entry# with
|
|
Packit |
df99a1 |
argument #arg#. The thread terminates when the function returns. A
|
|
Packit |
df99a1 |
thread cannot be restarted after its termination. You must create a new
|
|
Packit |
df99a1 |
#GThread# object. */
|
|
Packit |
df99a1 |
int create(void (*entry)(void*), void *arg);
|
|
Packit |
df99a1 |
/** Terminates a thread with extreme prejudice. The thread is removed from
|
|
Packit |
df99a1 |
the scheduling list. Execution terminates regardless of the execution
|
|
Packit |
df99a1 |
status of the thread function. Automatic variables may or may not be
|
|
Packit |
df99a1 |
destroyed. This function must be considered as a last resort since
|
|
Packit |
df99a1 |
memory may be lost. */
|
|
Packit |
df99a1 |
void terminate();
|
|
Packit |
df99a1 |
/** Causes the current thread to relinquish the processor. The scheduler
|
|
Packit |
df99a1 |
selects a thread ready to run and transfers control to that thread. The
|
|
Packit |
df99a1 |
actual effect of #yield# heavily depends on the selected implementation.
|
|
Packit |
df99a1 |
Function #yield# usually returns zero when the execution of the current
|
|
Packit |
df99a1 |
thread is resumed. It may return a positive number when it can
|
|
Packit |
df99a1 |
determine that the current thread will remain the only runnable thread
|
|
Packit |
df99a1 |
for some time. You may then call function \Ref{get_select} to
|
|
Packit |
df99a1 |
obtain more information. */
|
|
Packit |
df99a1 |
static int yield();
|
|
Packit |
df99a1 |
/** Returns a value which uniquely identifies the current thread. */
|
|
Packit |
df99a1 |
static void *current();
|
|
Packit |
df99a1 |
#if WINTHREADS
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
HANDLE hthr;
|
|
Packit |
df99a1 |
DWORD thrid;
|
|
Packit |
df99a1 |
#elif POSIXTHREADS
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
pthread_t hthr;
|
|
Packit |
df99a1 |
static void *start(void *arg);
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
// Should be considered as private
|
|
Packit |
df99a1 |
void (*xentry)(void*);
|
|
Packit |
df99a1 |
void *xarg;
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
// Disable default members
|
|
Packit |
df99a1 |
GThread(const GThread&);
|
|
Packit |
df99a1 |
GThread& operator=(const GThread&);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** Monitor class. Monitors have been first described in (C.A.R Hoare,
|
|
Packit |
df99a1 |
Communications of the ACM, 17(10), 1974). This mechanism provides the
|
|
Packit |
df99a1 |
basic mutual exclusion (mutex) and thread notification facilities
|
|
Packit |
df99a1 |
(condition variables).
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
Only one thread can own the monitor at a given time. Functions
|
|
Packit |
df99a1 |
\Ref{enter} and \Ref{leave} can be used to acquire and release the
|
|
Packit |
df99a1 |
monitor. This mutual exclusion provides an efficient way to protect
|
|
Packit |
df99a1 |
segment of codes ({\em critical sections}) which should not be
|
|
Packit |
df99a1 |
simultaneously executed by two threads. Class \Ref{GMonitorLock} provides
|
|
Packit |
df99a1 |
a convenient way to do this effectively.
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
When the thread owning the monitor calls function \Ref{wait}, the monitor
|
|
Packit |
df99a1 |
is released and the thread starts waiting until another thread calls
|
|
Packit |
df99a1 |
function \Ref{signal} or \Ref{broadcast}. When the thread wakes-up, it
|
|
Packit |
df99a1 |
re-acquires the monitor and function #wait# returns. Since the signaling
|
|
Packit |
df99a1 |
thread must acquire the monitor before calling functions #signal# and
|
|
Packit |
df99a1 |
#broadcast#, the signaled thread will not be able to re-acquire the
|
|
Packit |
df99a1 |
monitor until the signaling thread(s) releases the monitor.
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
{\bf Note} --- Both the copy constructor and the copy operator are declared
|
|
Packit |
df99a1 |
as private members. It is therefore not possible to make multiple copies
|
|
Packit |
df99a1 |
of instances of this class, as implied by the class semantic. */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class GMonitor
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
GMonitor();
|
|
Packit |
df99a1 |
~GMonitor();
|
|
Packit |
df99a1 |
/** Enters the monitor. If the monitor is acquired by another thread this
|
|
Packit |
df99a1 |
function waits until the monitor is released. The current thread then
|
|
Packit |
df99a1 |
acquires the monitor. Calls to #enter# and #leave# may be nested. */
|
|
Packit |
df99a1 |
void enter();
|
|
Packit |
df99a1 |
/** Leaves the monitor. The monitor counts how many times the current
|
|
Packit |
df99a1 |
thread has entered the monitor. Function #leave# decrement this count.
|
|
Packit |
df99a1 |
The monitor is released when this count reaches zero. An exception is
|
|
Packit |
df99a1 |
thrown if this function is called by a thread which does not own the
|
|
Packit |
df99a1 |
monitor. */
|
|
Packit |
df99a1 |
void leave();
|
|
Packit |
df99a1 |
/** Waits until the monitor is signaled. The current thread atomically
|
|
Packit |
df99a1 |
releases the monitor and waits until another thread calls function
|
|
Packit |
df99a1 |
#signal# or #broadcast#. Function #wait# then re-acquires the monitor
|
|
Packit |
df99a1 |
and returns. An exception is thrown if this function is called by a
|
|
Packit |
df99a1 |
thread which does not own the monitor. */
|
|
Packit |
df99a1 |
void wait();
|
|
Packit |
df99a1 |
/** Waits until the monitor is signaled or a timeout is reached. The
|
|
Packit |
df99a1 |
current thread atomically releases the monitor and waits until another
|
|
Packit |
df99a1 |
thread calls function #signal# or #broadcast# or a maximum of #timeout#
|
|
Packit |
df99a1 |
milliseconds. Function #wait# then re-acquires the monitor and returns.
|
|
Packit |
df99a1 |
An exception is thrown if this function is called by a thread which does
|
|
Packit |
df99a1 |
not own the monitor. */
|
|
Packit |
df99a1 |
void wait(unsigned long timeout);
|
|
Packit |
df99a1 |
/** Signals one waiting thread. Function #signal# wakes up at most one of
|
|
Packit |
df99a1 |
the waiting threads for this monitor. An exception is thrown if this
|
|
Packit |
df99a1 |
function is called by a thread which does not own the monitor. */
|
|
Packit |
df99a1 |
void signal();
|
|
Packit |
df99a1 |
/** Signals all waiting threads. Function #broadcast# wakes up all the
|
|
Packit |
df99a1 |
waiting threads for this monitor. An exception is thrown if this
|
|
Packit |
df99a1 |
function is called by a thread which does not own the monitor. */
|
|
Packit |
df99a1 |
void broadcast();
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
#if WINTHREADS
|
|
Packit |
df99a1 |
int ok;
|
|
Packit |
df99a1 |
int count;
|
|
Packit |
df99a1 |
DWORD locker;
|
|
Packit |
df99a1 |
CRITICAL_SECTION cs;
|
|
Packit |
df99a1 |
struct thr_waiting *head;
|
|
Packit |
df99a1 |
struct thr_waiting *tail;
|
|
Packit |
df99a1 |
#elif POSIXTHREADS
|
|
Packit |
df99a1 |
int ok;
|
|
Packit |
df99a1 |
int count;
|
|
Packit |
df99a1 |
pthread_t locker;
|
|
Packit |
df99a1 |
pthread_mutex_t mutex;
|
|
Packit |
df99a1 |
pthread_cond_t cond;
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
// Disable default members
|
|
Packit |
df99a1 |
GMonitor(const GMonitor&);
|
|
Packit |
df99a1 |
GMonitor& operator=(const GMonitor&);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// ----------------------------------------
|
|
Packit |
df99a1 |
// SCOPE LOCK
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** Wrapper for mutually exclusive code.
|
|
Packit |
df99a1 |
This class locks a specified critical section (see \Ref{GCriticalSection})
|
|
Packit |
df99a1 |
at construction time and unlocks it at destruction time. It provides a
|
|
Packit |
df99a1 |
convenient way to take advantage of the C++ implicit destruction of
|
|
Packit |
df99a1 |
automatic variables in order to make sure that the monitor is
|
|
Packit |
df99a1 |
released when exiting the protected code. The following code will release
|
|
Packit |
df99a1 |
the monitor when the execution thread leaves the protected scope, either
|
|
Packit |
df99a1 |
because the protected code has executed successfully, or because an
|
|
Packit |
df99a1 |
exception was thrown.
|
|
Packit |
df99a1 |
\begin{verbatim}
|
|
Packit |
df99a1 |
{ -- protected scope
|
|
Packit |
df99a1 |
static GMonitor theMonitor;
|
|
Packit |
df99a1 |
GMonitorLock lock(&theMonitor)
|
|
Packit |
df99a1 |
... -- protected code
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
\end{verbatim}
|
|
Packit |
df99a1 |
This construct will do nothing when passed a null pointer.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
class GMonitorLock
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
GMonitor *gsec;
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
/** Constructor. Enters the monitor #gsec#. */
|
|
Packit |
df99a1 |
GMonitorLock(GMonitor *gsec) : gsec(gsec)
|
|
Packit |
df99a1 |
{ if (gsec) gsec->enter(); };
|
|
Packit |
df99a1 |
/** Destructor. Leaves the associated monitor. */
|
|
Packit |
df99a1 |
~GMonitorLock()
|
|
Packit |
df99a1 |
{ if (gsec) gsec->leave(); };
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// ----------------------------------------
|
|
Packit |
df99a1 |
// GSAFEFLAGS (LB: this is not foolproof-safe but can be used savely!)
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** A thread safe class representing a set of flags. The flags are protected
|
|
Packit |
df99a1 |
by \Ref{GMonitor}, which is attempted to be locked whenever somebody
|
|
Packit |
df99a1 |
accesses the flags. One can modify the class contents using one of
|
|
Packit |
df99a1 |
two functions: \Ref{test_and_modify}() and \Ref{wait_and_modify}().
|
|
Packit |
df99a1 |
Both of them provide atomic operation of testing (first) and modification
|
|
Packit |
df99a1 |
(second). The flags remain locked between the moment of testing and
|
|
Packit |
df99a1 |
modification, which guarantees, that their state cannot be changed in
|
|
Packit |
df99a1 |
between of these operations. */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class GSafeFlags : public GMonitor
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
volatile long flags;
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
/// Constructs #GSafeFlags# object.
|
|
Packit |
df99a1 |
GSafeFlags(long flags=0);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** Assignment operator. Will also wake up threads waiting for the
|
|
Packit |
df99a1 |
flags to change. */
|
|
Packit |
df99a1 |
GSafeFlags & operator=(long flags);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** Returns the value of the flags */
|
|
Packit |
df99a1 |
operator long(void) const;
|
|
Packit |
df99a1 |
/** Modifies the flags by ORing them with the provided mask. A broadcast
|
|
Packit |
df99a1 |
will be sent after the modification is done. */
|
|
Packit |
df99a1 |
GSafeFlags & operator|=(long mask);
|
|
Packit |
df99a1 |
/** Modifies the flags by ANDing them with the provided mask. A broadcast
|
|
Packit |
df99a1 |
will be sent after the modification is done. */
|
|
Packit |
df99a1 |
GSafeFlags & operator&=(long mask);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** If all bits mentioned in #set_mask# are set in the flags and all
|
|
Packit |
df99a1 |
bits mentioned in #clr_mask# are cleared in the flags, it sets all
|
|
Packit |
df99a1 |
bits from #set_mask1# in the flags, clears all flags from
|
|
Packit |
df99a1 |
#clr_mask1# in the flags and returns #TRUE#. Otherwise returns
|
|
Packit |
df99a1 |
#FALSE#. */
|
|
Packit |
df99a1 |
bool test_and_modify(long set_mask, long clr_mask,
|
|
Packit |
df99a1 |
long set_mask1, long clr_mask1);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** Waits until all bits mentioned in #set_mask# are set in the flags
|
|
Packit |
df99a1 |
and all bits mentioned in #clr_flags# are cleared in the flags.
|
|
Packit |
df99a1 |
After that it sets bits from #set_mask1# and clears bits from
|
|
Packit |
df99a1 |
#clr_mask1# in the flags. */
|
|
Packit |
df99a1 |
void wait_and_modify(long set_mask, long clr_mask,
|
|
Packit |
df99a1 |
long set_mask1, long clr_mask1);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** Waits until all bits set in #set_mask# are set in the flags and
|
|
Packit |
df99a1 |
all bits mentioned in #clr_mask# are cleared in the flags. */
|
|
Packit |
df99a1 |
void wait_for_flags(long set_mask, long clr_mask=0) const;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/** Modifies the flags by setting all bits mentioned in #set_mask#
|
|
Packit |
df99a1 |
and clearing all bits mentioned in #clr_mask#. If the flags have
|
|
Packit |
df99a1 |
actually been modified, a broadcast will be sent. */
|
|
Packit |
df99a1 |
void modify(long set_mask, long clr_mask);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
inline
|
|
Packit |
df99a1 |
GSafeFlags::GSafeFlags(long xflags)
|
|
Packit |
df99a1 |
: flags(xflags)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
inline void
|
|
Packit |
df99a1 |
GSafeFlags::wait_for_flags(long set_mask, long clr_mask) const
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
((GSafeFlags *) this)->wait_and_modify(set_mask, clr_mask, 0, 0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
inline void
|
|
Packit |
df99a1 |
GSafeFlags::modify(long set_mask, long clr_mask)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
test_and_modify(0, 0, set_mask, clr_mask);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
inline GSafeFlags &
|
|
Packit |
df99a1 |
GSafeFlags::operator|=(long mask)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
test_and_modify(0, 0, mask, 0);
|
|
Packit |
df99a1 |
return *this;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
inline GSafeFlags &
|
|
Packit |
df99a1 |
GSafeFlags::operator&=(long mask)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
test_and_modify(0, 0, 0, ~mask);
|
|
Packit |
df99a1 |
return *this;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
//@}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// ----------------------------------------
|
|
Packit |
df99a1 |
// COMPATIBILITY CLASSES
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- these classes are no longer documented.
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class GCriticalSection : protected GMonitor
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
void lock()
|
|
Packit |
df99a1 |
{ GMonitor::enter(); };
|
|
Packit |
df99a1 |
void unlock()
|
|
Packit |
df99a1 |
{ GMonitor::leave(); };
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class GEvent : protected GMonitor
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
int status;
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
GEvent()
|
|
Packit |
df99a1 |
: status(0) { };
|
|
Packit |
df99a1 |
void set()
|
|
Packit |
df99a1 |
{ if (!status) { enter(); status=1; signal(); leave(); } };
|
|
Packit |
df99a1 |
void wait()
|
|
Packit |
df99a1 |
{ enter(); if (!status) GMonitor::wait(); status=0; leave(); };
|
|
Packit |
df99a1 |
void wait(int timeout)
|
|
Packit |
df99a1 |
{ enter(); if (!status) GMonitor::wait(timeout); status=0; leave(); };
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class GCriticalSectionLock
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
GCriticalSection *gsec;
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
GCriticalSectionLock(GCriticalSection *gsec) : gsec(gsec)
|
|
Packit |
df99a1 |
{ if (gsec) gsec->lock(); };
|
|
Packit |
df99a1 |
~GCriticalSectionLock()
|
|
Packit |
df99a1 |
{ if (gsec) gsec->unlock(); };
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// ----------------------------------------
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef HAVE_NAMESPACES
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
# ifndef NOT_USING_DJVU_NAMESPACE
|
|
Packit |
df99a1 |
using namespace DJVU;
|
|
Packit |
df99a1 |
# endif
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
#endif //_GTHREADS_H_
|
|
Packit |
df99a1 |
|