From 914fe0ed606bdfbcafc9fe74596bbe7fe09a8e68 Mon Sep 17 00:00:00 2001 From: chatty Date: Tue, 28 Nov 2000 17:07:44 +0000 Subject: * Meilleures verifications de NFILE, en attendant mieux --- comm/Multiplexer.cc | 143 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 93 insertions(+), 50 deletions(-) (limited to 'comm/Multiplexer.cc') diff --git a/comm/Multiplexer.cc b/comm/Multiplexer.cc index 1edb225..b879ce6 100644 --- a/comm/Multiplexer.cc +++ b/comm/Multiplexer.cc @@ -3,7 +3,7 @@ * * by Michel Beaudouin-Lafon * - * Copyright 1990-1996 + * Copyright 1990-1997 * Laboratoire de Recherche en Informatique (LRI) * * Channel sets, or multiplexers @@ -13,8 +13,8 @@ */ #include "Multiplexer.h" -#include "../UCH/TimeOut.h" -#include "../UCH/SignalHandler.h" +#include "TimeOut.h" +#include "SignalHandler.h" #include // for NSIG #include @@ -36,7 +36,9 @@ extern "C" int select (int, fd_set*, fd_set*, fd_set*, struct timeval*); #endif -extern int errno; +extern int errno; + +UchBaseMultiplexer* UchMpx = 0; #ifndef FD_SET #ifndef NFDBITS @@ -62,7 +64,7 @@ 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. +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 @@ -83,11 +85,12 @@ 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 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. -The semantic 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. ?*/ /*? @@ -124,6 +127,7 @@ UchBaseMultiplexer :: ~UchBaseMultiplexer () 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. @@ -134,18 +138,18 @@ UchBaseMultiplexer :: operator [] (int fd) return (fd < 0 || fd >= NFILE) ? 0 : Channels [fd]; } -/*? -Add a channel to the set. Note that the argument is a pointer to -the channel; 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. +/*? +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) + if (fd < 0 || fd >= NFILE) return false; UchChannel* ochan = Channels [fd]; if (ochan) @@ -162,7 +166,7 @@ Remove a channel from the set. This function can be passed a \var{UchChannel}. bool UchBaseMultiplexer :: Remove (int fd) { - if (fd < 0) + if (fd < 0 || fd >= NFILE) return false; UchChannel* ch = Channels [fd]; if (ch) { @@ -262,7 +266,6 @@ UchBaseMultiplexer :: SetMasks (int, IOMODE) { } -#if 0 static jmp_buf reset_run; class UchMpxAborter : public UchBaseSignalHandler { @@ -270,7 +273,6 @@ public: UchMpxAborter (UchBaseMultiplexer& m, int s) : UchBaseSignalHandler (m, s) {} void DeferredHandle (int) { MyMpx.Abort (); } }; -#endif /*? Run a multiplexer: make it repeatedly scan its channels, and take the @@ -288,17 +290,15 @@ or signals SIGINT or SIGTERM were received.\\ MPX_RES UchBaseMultiplexer :: Run () { -#if 0 if (setjmp (reset_run)) return isMpxAborted; UchMpxAborter h1 (*this, SigTerm); UchMpxAborter h2 (*this, SigInt); -#endif + return Loop (); } -#if 0 /*? Remove all channels from the multiplexer, thus stopping it if running. ?*/ @@ -318,7 +318,6 @@ UchBaseMultiplexer :: Abort () if (Looping) longjmp (reset_run, 1); } -#endif /*?class UchMultiplexer The class \typ{UchMultiplexer} is the default implementation of multiplexers, @@ -334,6 +333,7 @@ UchMultiplexer :: UchMultiplexer () TimeOut (-1), Looping (false), Hooks () + { FD_ZERO (&ReadMask); FD_ZERO (&WriteMask); @@ -391,11 +391,36 @@ UchMultiplexer :: SetMasks (int fd, IOMODE mode) } -#ifdef 0 -Scan n'est plus a jour avec LoopScan et n'est jamais appelee de -toutes facons.... +#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) @@ -403,28 +428,20 @@ UchMultiplexer :: Scan (bool nointr, bool poll) fd_set rmsk, wmsk; int nfd, ret = -1; register int fd; - struct timeval tout; + struct timeval tv; struct timeval* timeout = 0; if (poll) { - timeout = &tout; - tout.tv_sec = tout.tv_usec = 0; + timeout = &tv; + tv.tv_sec = tv.tv_usec = 0; } while (ret <= 0) { - if (ReadCount == 0 && WriteCount == 0 && SelectCount == 0) + if (ReadCount == 0 && WriteCount == 0 && SelectCount == 0) { + ExecHooks (true); return 0; - -/* Old version with HandleSelect, to be replaced by Hooks - for (fd = 0, nfd = SelectCount; nfd; fd++) { - if (! FD_ISSET (fd, &SelectMask)) - continue; - UchChannel* ch = Channels [fd]; - if (ch && ch->HandleSelect ()) - return -2; - nfd--; } -*/ + ExecHooks (false); rmsk = ReadMask; wmsk = WriteMask; @@ -437,9 +454,9 @@ UchMultiplexer :: Scan (bool nointr, bool poll) /* if delay < 0, select is unhappy */ if (delay < 0) ret = 0; - tout.tv_sec = delay / 1000; - tout.tv_usec = 1000 * (delay % 1000); - timeout = &tout; + tv.tv_sec = delay / 1000; + tv.tv_usec = 1000 * (delay % 1000); + timeout = &tv; } /* skipping select is a trick to avoid problems with timers. However, @@ -447,9 +464,11 @@ UchMultiplexer :: Scan (bool nointr, bool poll) - 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... */ @@ -457,17 +476,23 @@ UchMultiplexer :: Scan (bool nointr, bool poll) else if (!poll) fprintf (stderr, "select returned 0 without reason!\n"); return 0; + + /* Handle errors */ } else if (ret < 0) { - if (nointr && errno == EINTR) + if (nointr && ret == -1 && errno == EINTR) continue; - else + else { + ExecHooks (true); return ret; + } } } - + + + /* Finally, handle pending input and output */ for (fd = 0, nfd = ret; nfd; fd++) { if (FD_ISSET (fd, &wmsk)) { - nfd --; + nfd--; UchChannel* ch = Channels [fd]; if (ch) ch->HandleWrite (); @@ -483,7 +508,6 @@ UchMultiplexer :: Scan (bool nointr, bool poll) return ret; } -#endif /* Scan */ /*? Scan the channels in the set and call the channel's handlers. @@ -502,14 +526,14 @@ 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{LoopEnd} is called, or +\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{LoopEnd} or \fun{Close} was called. +and it returns \var{isMpxTerminated} if \fun{Stop} or \fun{Close} was called. ?*/ MPX_RES UchMultiplexer :: LoopScan (bool nointr) @@ -630,6 +654,7 @@ UchMultiplexer :: Loop () return LoopScan (); } + void UchMultiplexer :: Stop () { @@ -677,3 +702,21 @@ UchMultiplexer :: ExecHooks (bool final) } } +void +UchOpen (UchBaseMultiplexer* m) +{ + UchMpx = m ? m : new UchMultiplexer; + DnnMpx = UchMpx; +} + +MPX_RES +UchLoop () +{ + return UchMpx->Loop (); +} + +void +UchStop () +{ + UchMpx->Stop (); +} -- cgit v1.1