From ee937667fd0ecd82faab4c88d756b906fb625f1a Mon Sep 17 00:00:00 2001 From: sc Date: Tue, 28 Nov 2000 17:07:47 +0000 Subject: Integration into IvyLeague Uvh -> Ivl Multiplexer.* is renamed into Scheduler.* A few name conflicts in the merger with ex-DNN have been solved Imakefile is replaced by Makefile Created InetAddress.* and UnixAddress.* from Address.* Created IrdaAddress.* OLD/TextStream has been updated --- comm/Multiplexer.cc | 722 ---------------------------------------------------- 1 file changed, 722 deletions(-) delete mode 100644 comm/Multiplexer.cc (limited to 'comm/Multiplexer.cc') diff --git a/comm/Multiplexer.cc b/comm/Multiplexer.cc deleted file mode 100644 index b879ce6..0000000 --- a/comm/Multiplexer.cc +++ /dev/null @@ -1,722 +0,0 @@ -/* - * The Unix Channel - * - * by Michel Beaudouin-Lafon - * - * Copyright 1990-1997 - * Laboratoire de Recherche en Informatique (LRI) - * - * Channel sets, or multiplexers - * - * $Id$ - * $CurLog$ - */ - -#include "Multiplexer.h" -#include "TimeOut.h" -#include "SignalHandler.h" - -#include // for NSIG -#include -#include -#include - -#include -#include -#include -#include - -#if defined(__hpux) && !defined(__GNUG__) -#define FD_SET_TYPE(x) ((int*) x) -#else -#define FD_SET_TYPE(x) (x) -#endif - -#ifdef __osf__ -extern "C" int select (int, fd_set*, fd_set*, fd_set*, struct timeval*); -#endif - -extern int errno; - -UchBaseMultiplexer* UchMpx = 0; - -#ifndef FD_SET -#ifndef NFDBITS -#define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n))) -#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1 << (n))) -#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n))) -#define FD_ZERO(p) ((p)->fds_bits[0] = 0) -#else -#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) -#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) -#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) -#define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p))) -#endif -#endif - - -/*?class UchBaseMultiplexer -Multiplexers make it possible to handle several communication channels at the -same time; their implementation is based on the Unix \com{select} system call -or similar mechanisms. Multiplexers are also able to implement safe (ie. not -interruption-based) timers and signal handlers. - -Some of the channels in the set are active, others can be inactive. A -multiplexer can be scanned so that the functions \fun{HandleRead} and -\fun{HandleWrite} are called for every active channel that is ready to -read or write. - -If a channel needs to perform a background task or buffer input/output, -it can add a hook on the multiplexer with \fun{AddHook} which will be -called before actually scanning. For example that's the case for a connection -with the X server, when some pending events have been buffered into the -client by the previous \fun{HandleRead} call and need to be processed. - -Multiplexers may have different implementations, depending on the -environment. When no other library is involved, they are simply -implemented on top of Unix. But if \uch\ channels have to be mixed -with the X Toolkit for instance, the implementation uses the -mechanisms provided by the X Toolkit to add new channels. The same -holds for Tcl/Tk or other environments. Every such implentation -corresponds to a derived class of \typ{UchBaseMultiplexer}, which -offers a uniform interface that hides the implementation -differences. See the class \typ{UchMultiplexer} for a ``pure \uch'' -implementation of multiplexers. - -Note that the functions that take an integer file descriptor as -argument can be passed a \typ{FILDES} or a \typ{UchChannel} because -the corresponding conversion operators are defined. - -The way to Add/Remove a channel from a multiplexer is to call -\fun{Add} and \fun{Remove} of the channel with the multiplexer as an -argument for the first one. - -?*/ - -/*? -Create an empty channel set. -?*/ -UchBaseMultiplexer :: UchBaseMultiplexer () -: DnnBaseMultiplexer (), - Channels (new (UchChannel*) [NFILE]), - Timers (), - ReadCount (0), - WriteCount (0), - SelectCount (0), - SigFired (false), - Handlers (new UchBaseSignalHandler* [NSIG]), - NbSignals (new int [NSIG]) -{ - memset (Handlers, 0, NSIG * sizeof (UchBaseSignalHandler*)); - memset (NbSignals, 0, NSIG * sizeof (int)); - memset (Channels, 0, NFILE * sizeof (UchChannel*)); -} - -/*?nodoc?*/ -UchBaseMultiplexer :: ~UchBaseMultiplexer () -{ -#ifdef CPLUS_BUG4 - delete [NFILE] Channels; - delete [NSIG] NbSignals; - delete [NSIG] Handlers; -#else - delete [] Channels; - delete [] NbSignals; - delete [] Handlers; -#endif - Channels = 0; -} - - -/*? -This array operator returns a pointer to the channel corresponding to file descriptor \var{fd}. -If there is no such channel in this channel set, the operator returns NIL. -?*/ -UchChannel* -UchBaseMultiplexer :: operator [] (int fd) -{ - return (fd < 0 || fd >= NFILE) ? 0 : Channels [fd]; -} - -/*? -Add a channel to the multiplexer. No copy is made by this -function. If a channel with the same file descriptor as the one being -added is already in the set, the old channel is first removed. That -means that for a given file descriptor, there can be only one channel -working on it at a time. -?*/ -bool -UchBaseMultiplexer :: Add (UchChannel* chan) -{ - int fd = chan->FilDes (); - if (fd < 0 || fd >= NFILE) - return false; - UchChannel* ochan = Channels [fd]; - if (ochan) - ochan->Remove (); - Channels [fd] = chan; - SetMasks (fd, chan->IOMode ()); - return true; -} - - -/*? -Remove a channel from the set. This function can be passed a \var{UchChannel}. -?*/ -bool -UchBaseMultiplexer :: Remove (int fd) -{ - if (fd < 0 || fd >= NFILE) - return false; - UchChannel* ch = Channels [fd]; - if (ch) { - SetMasks (fd, IONone); - Channels [fd] = 0; - } - return true; -} - -/*? -Remove all channels from this channel set. -This function calls \fun{Remove} for all channels of the set. -This is a way of exiting from \fun{LoopScan}. -?*/ -void -UchBaseMultiplexer :: RemoveAll () -{ - for (int fd = 0; fd < NFILE; fd++) { - UchChannel* ch = Channels [fd]; - if (ch) - ch->Remove (); // Calls UchBaseMultiplexer::Remove - } -} - -/*? -Change the mode of a channel in the set. -Mode \var{IONone} makes the channel inactive (without removing it). -This function can be passed a \var{UchChannel}. -?*/ -void -UchBaseMultiplexer :: SetMode (int fd, IOMODE mode) -{ - if (fd < 0) - return; - - SetMasks (fd, mode); - Channels [fd] -> SetMode (mode); -} - - -/*! -This function is called by UchSignalHandlers when a signal is -received. It just stores the signal for future (and safe) handling. -!*/ -/*?hidden?*/ -void -UchBaseMultiplexer :: HandleSignal (UchBaseSignalHandler& h) -{ - if (!SigFired) - AddSignalHook (); - SigFired = true; - int sig = h.GetSignal () - 1; - /* We have to work with arrays, because we are in a signal - handler, and we cannot use lists */ - Handlers [sig] = &h; - NbSignals [sig]++; - -} - -/*! -This virtual function is called the first time when a signal is received by a -signal handler associated to the multiplexer. It makes it possible -to call implementation-dependant functions that defer the handling to -safer times. -!*/ -/* -Does not need to be defined in UchMultiplexer, because -they use the flag SigFired. -*/ -/*?hidden?*/ -void -UchBaseMultiplexer :: AddSignalHook () -{ -} - -/*! -This function triggers the handling of all deferred signals. It should be -called when \fun{AddSignalHook} has been called and the times are safe. -!*/ -/*?hidden?*/ -void -UchBaseMultiplexer :: HandleDeferredSignals () -{ - CcuSignalBlocker b (AllSigs); - int c; - for (int i = 0; i < NSIG; ++i) - if (c = NbSignals [i]) { - Handlers [i]->DeferredHandle (c); - NbSignals [i] = 0; - Handlers [i] = 0; - } -} - -/*?hidden?*/ -void -UchBaseMultiplexer :: SetMasks (int, IOMODE) -{ -} - -static jmp_buf reset_run; - -class UchMpxAborter : public UchBaseSignalHandler { -public: - UchMpxAborter (UchBaseMultiplexer& m, int s) : UchBaseSignalHandler (m, s) {} - void DeferredHandle (int) { MyMpx.Abort (); } -}; - -/*? -Run a multiplexer: make it repeatedly scan its channels, and take the -appropriate actions. This function will exit under a number of -circumstances, reflected by its return value. -\small -\begin{tabular}{ll} -\var{isMpxTerminated}&the method \fun{Close} has been called.\\ -\var{isMpxEmpty}&there are no more channels in the set.\\ -\var{isMpxAborted}&the method \fun{Abort} has been called, -or signals SIGINT or SIGTERM were received.\\ -\var{isMpxError}&an error has occured. -\end{tabular} -?*/ -MPX_RES -UchBaseMultiplexer :: Run () -{ - if (setjmp (reset_run)) - return isMpxAborted; - - UchMpxAborter h1 (*this, SigTerm); - UchMpxAborter h2 (*this, SigInt); - - return Loop (); -} - -/*? -Remove all channels from the multiplexer, thus stopping it if running. -?*/ -void -UchBaseMultiplexer :: Close () -{ - RemoveAll (); - Looping = false; -} - -/*? -Stop the multiplexer, without cleaning it. -?*/ -void -UchBaseMultiplexer :: Abort () -{ - if (Looping) - longjmp (reset_run, 1); -} - -/*?class UchMultiplexer -The class \typ{UchMultiplexer} is the default implementation of multiplexers, -used when there are no compatibility needs. For historical reasons, it offers -a number of additional methods. -?*/ - -/*? -Build an empty multiplexer. -?*/ -UchMultiplexer :: UchMultiplexer () -: UchBaseMultiplexer (), - TimeOut (-1), - Looping (false), - Hooks () - -{ - FD_ZERO (&ReadMask); - FD_ZERO (&WriteMask); - FD_ZERO (&SelectMask); -} - -/*?nodoc?*/ -UchMultiplexer :: ~UchMultiplexer () -{ -} - - - -// update the masks when channel fd changes its mode -// -/*?hidden?*/ -void -UchMultiplexer :: SetMasks (int fd, IOMODE mode) -{ - if (mode & IORead) { - if (! FD_ISSET (fd, &ReadMask)) { - ReadCount++; - FD_SET (fd, &ReadMask); - } - } else { - if (FD_ISSET (fd, &ReadMask)) { - FD_CLR (fd, &ReadMask); - ReadCount--; - } - } - - if (mode & IOWrite) { - if (! FD_ISSET (fd, &WriteMask)) { - WriteCount++; - FD_SET (fd, &WriteMask); - } - } else { - if (FD_ISSET (fd, &WriteMask)) { - FD_CLR (fd, &WriteMask); - WriteCount--; - } - } - - if (mode & IOSelect) { - if (! FD_ISSET (fd, &SelectMask)) { - SelectCount++; - FD_SET (fd, &SelectMask); - } - } else { - if (FD_ISSET (fd, &SelectMask)) { - FD_CLR (fd, &SelectMask); - SelectCount--; - } - } - -} - -#if 0 -/*? -This function calls the select handler of each channel of the set in select mode. -It returns true as soon as one select handler returns true, -else it returns false when the select handlers have been called. -?*/ -bool -UchMultiplexer :: HandleSelect () -{ - int fd, nfd; - - if (fd0 >= NFILE) - fd0 = 0; - for (fd = fd0++, nfd = SelectCount; nfd; (fd < NFILE) ? fd++ : (fd = 0)) { - if (! FD_ISSET (fd, &SelectMask)) - continue; - if (Channels [fd] -> HandleSelect ()) - return true; - nfd--; - if (! Looping) - return false; - } - return false; -} - -#endif - -////// should add signal handling -////// Hooks are probably badly handled -////// Scan should disappear anyway. Only use is in Xtv. -/*?nextdoc?*/ -int -UchMultiplexer :: Scan (bool nointr, bool poll) -{ - fd_set rmsk, wmsk; - int nfd, ret = -1; - register int fd; - struct timeval tv; - struct timeval* timeout = 0; - - if (poll) { - timeout = &tv; - tv.tv_sec = tv.tv_usec = 0; - } - - while (ret <= 0) { - if (ReadCount == 0 && WriteCount == 0 && SelectCount == 0) { - ExecHooks (true); - return 0; - } - ExecHooks (false); - - rmsk = ReadMask; - wmsk = WriteMask; - - /* let's fiddle with ret to skip select if we are late with timers */ - ret = -1; - if (!poll && TimeOut != -1) { - CcuTimeStamp now; - Millisecond delay = TimeOut - now; - /* if delay < 0, select is unhappy */ - if (delay < 0) - ret = 0; - tv.tv_sec = delay / 1000; - tv.tv_usec = 1000 * (delay % 1000); - timeout = &tv; - } - - /* skipping select is a trick to avoid problems with timers. However, - something more general should be done to: - - manage priorities (I'm not sure the current situation is sound) - - handle situations when we are late. - */ - /* Call select, except if late with timers */ - if (ret != 0) - ret = select (NFILE, FD_SET_TYPE(&rmsk), FD_SET_TYPE(&wmsk), 0, timeout); - - /* Handle time out */ - if (ret == 0) { - if (TimeOut != -1) - /* Fire might be called without reason if polling is on. Too bad... */ - CcuCoreTimer::Fire (&Timers); - else if (!poll) - fprintf (stderr, "select returned 0 without reason!\n"); - return 0; - - /* Handle errors */ - } else if (ret < 0) { - if (nointr && ret == -1 && errno == EINTR) - continue; - else { - ExecHooks (true); - return ret; - } - } - } - - - /* Finally, handle pending input and output */ - for (fd = 0, nfd = ret; nfd; fd++) { - if (FD_ISSET (fd, &wmsk)) { - nfd--; - UchChannel* ch = Channels [fd]; - if (ch) - ch->HandleWrite (); - } - if (FD_ISSET (fd, &rmsk)) { - nfd--; - UchChannel* ch = Channels [fd]; - if (ch) - ch->HandleRead (); - } - } - - return ret; -} - - -/*? -Scan the channels in the set and call the channel's handlers. -First the select handler (\fun{UchChannel::HandleSelect}) of each channel with mode -\var{IOSelect} is called. -If it returns true, \fun{Scan} exits immediately, while \fun{LoopScan} loops immediately. -If no select handler returns true, the system call \fun{select} is used to poll or -wait for the channels that are ready. -When the select returns normally, the write handlers \fun{HandleWrite} of the -channels in mode \var{IOWrite} that are ready to write are called, and -the read handlers (\fun{HandleRead}) of the channels in mode \fun{IORead} -that are ready to read are called. -If \var{nointr} is true, ignore the interrupted system calls, else return an error -whenever the \fun{select} system call is interrupted. -If \var{poll} is true, the call is non-blocking, else it is blocking. -\fun{Scan} calls \fun{select} only once; -it returns -2 if a select handler returns, it returns 0 if the channel set has no active channels, -else it returns the return code of \fun{select}. -\fun{LoopScan} calls \fun{select} repeatedly until \var{Stop} is called, or -an error occurs, the channel set has no more active channel -This can occur because the select, read or write handler of a channel may remove -the channel or change its mode. -This is usually done when the read handler detects an end of file. -\fun{LoopScan} returns \var{isMpxEmpty} when there are no more active channel in the set, -it returns \var{isMpxError} when an error occured (the code is in \var{errno}), -and it returns \var{isMpxTerminated} if \fun{Stop} or \fun{Close} was called. -?*/ -MPX_RES -UchMultiplexer :: LoopScan (bool nointr) -{ - fd_set rmsk, wmsk; - register int nb_pending_fd, fd, fd0; - Looping = true; - - for (fd0 = 0; Looping; fd0 < NFILE ? fd0++ : (fd0 = 0)) { - - /* First, handle signals */ - if (SigFired) - HandleDeferredSignals (); - -#if 0 - /* Then, timers */ - CcuCoreTimer::Fire (&Timers); -#endif - /* Then, check I/Os */ - if (ReadCount == 0 && WriteCount == 0 && SelectCount == 0) { - ExecHooks (true); - return isMpxEmpty; - } - - /* Then other hooks */ - ExecHooks (false); - - /* Lets get ready for calling select: set masks and compute next time out. - We fiddle with nb_pending_fd to skip select if we are late with timers */ - nb_pending_fd = -1; - rmsk = ReadMask; - wmsk = WriteMask; - struct timeval tv; - struct timeval* timeout = 0; - if (TimeOut != -1) { - CcuTimeStamp now; - Millisecond delay = TimeOut - now; - if (delay < 0) - nb_pending_fd = 0; - tv.tv_sec = delay / 1000; - tv.tv_usec = 1000 * (delay % 1000); - timeout = &tv; - } - - /* Call select, except if late with timers */ - if (nb_pending_fd != 0) - nb_pending_fd = select (NFILE, FD_SET_TYPE(&rmsk), FD_SET_TYPE(&wmsk), 0, timeout); - /* Handle time out */ - if (nb_pending_fd == 0) { - if (TimeOut != -1) - CcuCoreTimer::Fire (&Timers); - else - fprintf (stderr, "select returned 0 without reason!\n"); - continue; - - /* Handle errors */ - } else if (nb_pending_fd < 0) { - if (nointr && nb_pending_fd == -1 && errno == EINTR) - continue; - else { - ExecHooks (true); - return isMpxError; - } - } - - /* Finally, handle pending input and output */ - for (fd = fd0; nb_pending_fd; (fd < NFILE) ? fd++ : (fd = 0)) { - if (FD_ISSET (fd, &wmsk)) { - nb_pending_fd--; - Channels[fd]->HandleWrite (); - if (! Looping) { - ExecHooks (true); - return isMpxTerminated; - } - } - if (FD_ISSET (fd, &rmsk)) { - nb_pending_fd--; - Channels[fd]->HandleRead (); - if (! Looping) { - ExecHooks (true); - return isMpxTerminated; - } - } - } - } - - ExecHooks (true); - return isMpxTerminated; -} - -/*?nodoc?*/ -char* -UchMultiplexer :: StrRepr (char* buf) -{ - sprintf (buf, "R:%ux W:%ux", ReadMask, WriteMask); - return buf; -} - -/*?hidden?*/ -void -UchMultiplexer :: SetTimeOut (Millisecond delay) -{ - CcuTimeStamp now; - TimeOut = now + delay; -} - -/*?hidden?*/ -void -UchMultiplexer :: SuppressTimeOut () -{ - TimeOut = -1; -} - -/*?hidden?*/ -MPX_RES -UchMultiplexer :: Loop () -{ - return LoopScan (); -} - - -void -UchMultiplexer :: Stop () -{ - Looping = false; -} - - -void -UchMultiplexer :: AddHook (UchMpxHook* h, bool final) -{ - Hooks.Append ((void*) h); - if (final) - FinalHooks.Append ((void*) h); -} - -void -UchMultiplexer :: RemoveHook (UchMpxHook* h, bool final) -{ - Hooks.Remove ((void*) h); - if (final) - FinalHooks.Remove ((void*) h); -} - -void -UchMultiplexer :: AddFinalHook (UchMpxHook* h) -{ - FinalHooks.Append ((void*) h); -} - -void -UchMultiplexer :: RemoveFinalHook (UchMpxHook* h) -{ - FinalHooks.Remove ((void*) h); -} - - -void -UchMultiplexer :: ExecHooks (bool final) -{ - CcuList* hooks = final ? &FinalHooks : &Hooks; - CcuListIter li = *hooks; - while (++li) { - UchMpxHook* h = (UchMpxHook*) *li; - (*h)(); - } -} - -void -UchOpen (UchBaseMultiplexer* m) -{ - UchMpx = m ? m : new UchMultiplexer; - DnnMpx = UchMpx; -} - -MPX_RES -UchLoop () -{ - return UchMpx->Loop (); -} - -void -UchStop () -{ - UchMpx->Stop (); -} -- cgit v1.1