summaryrefslogtreecommitdiff
path: root/comm
diff options
context:
space:
mode:
authorchatty2000-11-28 17:07:41 +0000
committerchatty2000-11-28 17:07:41 +0000
commit66caeca4d381a66409c3fc4e812a3e2e99fae081 (patch)
tree76d2ad33e700fed53c7862c326e8253ba425d73c /comm
parent4eb666da31191588d89629ebc38ee98f02ee89b4 (diff)
downloadivy-league-66caeca4d381a66409c3fc4e812a3e2e99fae081.zip
ivy-league-66caeca4d381a66409c3fc4e812a3e2e99fae081.tar.gz
ivy-league-66caeca4d381a66409c3fc4e812a3e2e99fae081.tar.bz2
ivy-league-66caeca4d381a66409c3fc4e812a3e2e99fae081.tar.xz
Modification du mecanisme d'ajout d'un Channel
Remplacement du HandleSelect par un systeme de Hook Integration avec DnnMultiplexer
Diffstat (limited to 'comm')
-rw-r--r--comm/Multiplexer.cc315
1 files changed, 178 insertions, 137 deletions
diff --git a/comm/Multiplexer.cc b/comm/Multiplexer.cc
index c1bf8b6..1edb225 100644
--- a/comm/Multiplexer.cc
+++ b/comm/Multiplexer.cc
@@ -3,7 +3,7 @@
*
* by Michel Beaudouin-Lafon
*
- * Copyright 1990-1995
+ * Copyright 1990-1996
* Laboratoire de Recherche en Informatique (LRI)
*
* Channel sets, or multiplexers
@@ -13,8 +13,8 @@
*/
#include "Multiplexer.h"
-#include "TimeOut.h"
-#include "SignalHandler.h"
+#include "../UCH/TimeOut.h"
+#include "../UCH/SignalHandler.h"
#include <signal.h> // for NSIG
#include <sys/errno.h>
@@ -58,41 +58,55 @@ 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.
-The functions \fun{HandleSelect} of each channel is called before actually scanning
-so that each channel can perform a background task or buffer input/output.
-
-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.
+
+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 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.
?*/
/*?
Create an empty channel set.
?*/
UchBaseMultiplexer :: UchBaseMultiplexer ()
-: Channels (new pUchChannel [NFILE]),
+: DnnBaseMultiplexer (),
+ Channels (new (UchChannel*) [NFILE]),
Timers (),
ReadCount (0),
WriteCount (0),
SelectCount (0),
- Looping (false),
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?*/
@@ -100,6 +114,8 @@ UchBaseMultiplexer :: ~UchBaseMultiplexer ()
{
#ifdef CPLUS_BUG4
delete [NFILE] Channels;
+ delete [NSIG] NbSignals;
+ delete [NSIG] Handlers;
#else
delete [] Channels;
delete [] NbSignals;
@@ -109,41 +125,51 @@ UchBaseMultiplexer :: ~UchBaseMultiplexer ()
}
/*?
-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.
+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.
?*/
-void
+UchChannel*
+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.
+?*/
+bool
UchBaseMultiplexer :: Add (UchChannel* chan)
{
int fd = chan->FilDes ();
if (fd < 0)
- return;
- pUchChannel ochan = Channels [fd];
+ return false;
+ UchChannel* ochan = Channels [fd];
if (ochan)
- Remove (fd);
- chan->Added (*this);
+ ochan->Remove ();
Channels [fd] = chan;
SetMasks (fd, chan->IOMode ());
+ return true;
}
-pUchChannel NIL_CHAN (0);
/*?
Remove a channel from the set. This function can be passed a \var{UchChannel}.
?*/
-void
+bool
UchBaseMultiplexer :: Remove (int fd)
{
if (fd < 0)
- return;
+ return false;
UchChannel* ch = Channels [fd];
if (ch) {
- ch->Removed (*this);
SetMasks (fd, IONone);
Channels [fd] = 0;
}
+ return true;
}
/*?
@@ -154,8 +180,11 @@ This is a way of exiting from \fun{LoopScan}.
void
UchBaseMultiplexer :: RemoveAll ()
{
- for (int fd = 0; fd < NFILE; fd++)
- Remove (fd);
+ for (int fd = 0; fd < NFILE; fd++) {
+ UchChannel* ch = Channels [fd];
+ if (ch)
+ ch->Remove (); // Calls UchBaseMultiplexer::Remove
+ }
}
/*?
@@ -173,26 +202,6 @@ UchBaseMultiplexer :: SetMode (int fd, IOMODE mode)
Channels [fd] -> SetMode (mode);
}
-#ifdef DOC
-
-/*?
-This array operator returns a (smart) pointer to the channel corresponding to file descriptor \var{fd}.
-If there is no such channel in this channel set, the operator returns NIL.
-?*/
-pUchChannel
-UchBaseMultiplexer :: operator [] (int fd)
-{ }
-
-/*?
-Add a channel to the set.
-Here the argument is a reference, and a dynamically allocated copy of it is actually added.
-Compare with previous function.
-?*/
-void
-UchBaseMultiplexer :: Add (const UchChannel& ch)
-{ }
-
-#endif /* DOC */
/*!
This function is called by UchSignalHandlers when a signal is
@@ -253,6 +262,7 @@ UchBaseMultiplexer :: SetMasks (int, IOMODE)
{
}
+#if 0
static jmp_buf reset_run;
class UchMpxAborter : public UchBaseSignalHandler {
@@ -260,6 +270,7 @@ 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
@@ -277,15 +288,17 @@ 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.
?*/
@@ -305,6 +318,7 @@ UchBaseMultiplexer :: Abort ()
if (Looping)
longjmp (reset_run, 1);
}
+#endif
/*?class UchMultiplexer
The class \typ{UchMultiplexer} is the default implementation of multiplexers,
@@ -317,7 +331,9 @@ Build an empty multiplexer.
?*/
UchMultiplexer :: UchMultiplexer ()
: UchBaseMultiplexer (),
- TimeOut (-1)
+ TimeOut (-1),
+ Looping (false),
+ Hooks ()
{
FD_ZERO (&ReadMask);
FD_ZERO (&WriteMask);
@@ -339,66 +355,45 @@ UchMultiplexer :: SetMasks (int fd, IOMODE mode)
{
if (mode & IORead) {
if (! FD_ISSET (fd, &ReadMask)) {
- ReadCount ++;
+ ReadCount++;
FD_SET (fd, &ReadMask);
}
} else {
if (FD_ISSET (fd, &ReadMask)) {
FD_CLR (fd, &ReadMask);
- ReadCount --;
+ ReadCount--;
}
}
if (mode & IOWrite) {
if (! FD_ISSET (fd, &WriteMask)) {
- WriteCount ++;
+ WriteCount++;
FD_SET (fd, &WriteMask);
}
} else {
if (FD_ISSET (fd, &WriteMask)) {
FD_CLR (fd, &WriteMask);
- WriteCount --;
+ WriteCount--;
}
}
if (mode & IOSelect) {
if (! FD_ISSET (fd, &SelectMask)) {
- SelectCount ++;
+ SelectCount++;
FD_SET (fd, &SelectMask);
}
} else {
if (FD_ISSET (fd, &SelectMask)) {
FD_CLR (fd, &SelectMask);
- SelectCount --;
+ SelectCount--;
}
}
}
-/*?
-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;
-}
-
+#ifdef 0
+Scan n'est plus a jour avec LoopScan et n'est jamais appelee de
+toutes facons....
////// should add signal handling
/*?nextdoc?*/
@@ -419,7 +414,8 @@ UchMultiplexer :: Scan (bool nointr, bool poll)
while (ret <= 0) {
if (ReadCount == 0 && WriteCount == 0 && SelectCount == 0)
return 0;
-
+
+/* Old version with HandleSelect, to be replaced by Hooks
for (fd = 0, nfd = SelectCount; nfd; fd++) {
if (! FD_ISSET (fd, &SelectMask))
continue;
@@ -428,6 +424,7 @@ UchMultiplexer :: Scan (bool nointr, bool poll)
return -2;
nfd--;
}
+*/
rmsk = ReadMask;
wmsk = WriteMask;
@@ -486,6 +483,8 @@ UchMultiplexer :: Scan (bool nointr, bool poll)
return ret;
}
+#endif /* Scan */
+
/*?
Scan the channels in the set and call the channel's handlers.
First the select handler (\fun{UchChannel::HandleSelect}) of each channel with mode
@@ -516,9 +515,9 @@ MPX_RES
UchMultiplexer :: LoopScan (bool nointr)
{
fd_set rmsk, wmsk;
- register int nfd, fd;
+ register int nb_pending_fd, fd, fd0;
Looping = true;
-
+
for (fd0 = 0; Looping; fd0 < NFILE ? fd0++ : (fd0 = 0)) {
/* First, handle signals */
@@ -528,27 +527,19 @@ UchMultiplexer :: LoopScan (bool nointr)
#if 0
/* Then, timers */
CcuCoreTimer::Fire (&Timers);
-#endif
-
- /* Then, I/Os */
- if (ReadCount == 0 && WriteCount == 0 && SelectCount == 0)
+#endif
+ /* Then, check I/Os */
+ if (ReadCount == 0 && WriteCount == 0 && SelectCount == 0) {
+ ExecHooks (true);
return isMpxEmpty;
-
- for (fd = fd0, nfd = SelectCount; nfd; (fd < NFILE) ? fd++ : (fd = 0)) {
- if (! FD_ISSET (fd, &SelectMask))
- continue;
- UchChannel* ch = Channels [fd];
- if (ch && ch->HandleSelect ())
- break;
- nfd--;
- if (! Looping)
- return isMpxTerminated;
}
- if (nfd) // a handler returned true.
- continue;
- /* let's fiddle with ret to skip select if we are late with timers */
- nfd = -1;
+ /* 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;
@@ -557,41 +548,55 @@ UchMultiplexer :: LoopScan (bool nointr)
CcuTimeStamp now;
Millisecond delay = TimeOut - now;
if (delay < 0)
- nfd = 0;
+ nb_pending_fd = 0;
tv.tv_sec = delay / 1000;
tv.tv_usec = 1000 * (delay % 1000);
timeout = &tv;
}
- if (nfd != 0)
- nfd = select (NFILE, FD_SET_TYPE(&rmsk), FD_SET_TYPE(&wmsk), 0, timeout);
- if (nfd == 0) {
+
+ /* 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;
- } else if (nfd < 0) {
- if (nointr && nfd == -1 && errno == EINTR)
+
+ /* Handle errors */
+ } else if (nb_pending_fd < 0) {
+ if (nointr && nb_pending_fd == -1 && errno == EINTR)
continue;
- else
+ else {
+ ExecHooks (true);
return isMpxError;
+ }
}
- for (fd = fd0; nfd; (fd < NFILE) ? fd++ : (fd = 0)) {
+ /* Finally, handle pending input and output */
+ for (fd = fd0; nb_pending_fd; (fd < NFILE) ? fd++ : (fd = 0)) {
if (FD_ISSET (fd, &wmsk)) {
- nfd--;
- Channels [fd] -> HandleWrite ();
- if (! Looping)
+ nb_pending_fd--;
+ Channels[fd]->HandleWrite ();
+ if (! Looping) {
+ ExecHooks (true);
return isMpxTerminated;
+ }
}
if (FD_ISSET (fd, &rmsk)) {
- nfd--;
- Channels [fd] -> HandleRead ();
- if (! Looping)
+ nb_pending_fd--;
+ Channels[fd]->HandleRead ();
+ if (! Looping) {
+ ExecHooks (true);
return isMpxTerminated;
+ }
}
}
}
+
+ ExecHooks (true);
return isMpxTerminated;
}
@@ -603,18 +608,6 @@ UchMultiplexer :: StrRepr (char* buf)
return buf;
}
-#ifdef DOC
-// fake entries for inline functions
-/*?
-This function makes \fun{LoopScan} exit immediately.
-Thus it must be called from within a channel's handler.
-?*/
-void
-UchMultiplexer :: LoopEnd ()
-{ }
-
-#endif /* DOC */
-
/*?hidden?*/
void
UchMultiplexer :: SetTimeOut (Millisecond delay)
@@ -636,3 +629,51 @@ 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)();
+ }
+}
+