< Previous by Date Date Index Next by Date >
  Thread Index Next in Thread >

[reSIProcate] RE: [Resiprocate-devel] proposed poll interface, with implementation


Hi Jacob,  (reposted to correct mailing list)

This interface looks excellent. I've had a look at it and it looks like the
changes to the stack should be fairly minimal.

How do I add file descriptors to the fdEntryVector? There doesn't seem to be
an interface to do this. What does the isTransport parameter on
Poll::FDEntry constructor mean? How do I specify which StateBitMasks I want
to wait on when I construct a FDEntry?

I see how to use the RESIP_POLL_EXTERN methods to add file descriptors but
it doesn't seem like this interface is necessary unless the application is
also going to add in its own filedescriptors. Do you think that each
Transport object should have its own Poll object?

In your implementation of RESIP_POLL_IMPL_POLL do you copy the
_fdEntryVector into an array before each call to poll? How do you deal with
error conditions? Exceptions?

I'd like to take a crack at integrating your select and poll based
implementations into resiprocate. This should greatly simplify the
round-robin code in the TcpTransport and also greatly increase the number of
open tcp connections that we can support. With the select implementation, it
can continue to work on windows platforms as well.

Thanks,
Jason



> -----Original Message-----
> From: resiprocate-devel-admin@xxxxxxxxxxxxxxxxxxxxx
> [mailto:resiprocate-devel-admin@xxxxxxxxxxxxxxxxxxxxx]On Behalf Of Jacob
> Butcher
> Sent: Friday, November 07, 2003 8:29 PM
> To: resiprocate-devel@xxxxxxxxxxxxxxxxxxxxx
> Subject: [Resiprocate-devel] proposed poll interface, with
> implementation
>
>
> I hear that abstracting the select call to be efficient, fair, portable,
> and single-thread-friendly is a Good Thing.  So I wrote a class
> to wrap it,
> enclosed.  The basic idea is an interface that:
> - is implementable in terms of select, poll, or epoll
> - produces a sorted file descriptor sequence for easy round-robin ordering
> - has very little overhead
> - supports single-threaded applications.
> The basic method and best place to start reading is "wait", 210
> lines below.
>
> I also wrote select and poll based implementations, not enclosed.
>
>                                 Jacob Butcher
>
> ################
> # Poll.hxx
> ################################################################
> #ifndef RESIP_POLL_HXX
> #define RESIP_POLL_HXX
>
> // One of the following macros must be defined:
> //#define RESIP_POLL_IMPL_POLL
> #define RESIP_POLL_IMPL_SELECT
> //#define RESIP_POLL_IMPL_EPOLL  // Not yet implemented.
>
> /*
> Define this macro to support applications that must call system
> call "poll"
> or its ilk themselves rather than calling method "Poll::wait".
> */
> #define RESIP_POLL_EXTERN
>
> #include <vector>
> #ifdef RESIP_POLL_IMPL_POLL
> #include <sys/poll.h>
> #endif
> #ifdef RESIP_POLL_IMPL_SELECT
> #include <sys/time.h>
> #include <sys/types.h>
> #include <unistd.h>
> #endif
> #ifdef RESIP_POLL_EXTERN
> #include <map>
> #endif
>
> namespace resip {
>
> //////////////////////////////////////////////////////////////////
> /////////////
>
> /*
> This class abstracts the Unix system call "poll".
> It offers implementations in terms of "poll" itself, "epoll", and
> "select".
> (Respectively #ifdef'd by RESIP_POLL_IMPL_POLL,
> RESIP_POLL_IMPL_SELECT, and
> RESIP_POLL_IMPL_EPOLL.)
> File descriptors are wrapped by inner class "Poll::FDEntry".
> The actual "poll" call is represented by method "wait", or if an
> application
> wants to control the system call directly, it can instead use methods
> "beforeExternWait", "setEntryFDStateForExternWait", and "afterExternWait".
> (The latter are selected by #define-ing RESIP_POLL_EXTERN.)
> */
> class Poll {
>
>  public:
>
>   class FDEntry {
>
>     friend class Poll;
>
>    public:
>
>     typedef unsigned short StateBitMask; // FDStateBitMask |
> ResipStateBitMask.
>     enum FDStateBitMaskEnum {
>       fdsbmReadable       = 0x0001, // (POLLIN)
>       fdsbmWritable       = 0x0004, // (POLLOUT)
>       fdsbmError          = 0x0008, // (POLLERR)
>       fdsbmAll            = Poll::FDEntry::fdsbmReadable |
>                             Poll::FDEntry::fdsbmWritable |
>                             Poll::FDEntry::fdsbmError
>     };
>     typedef StateBitMask FDStateBitMask;
>     enum ResipStateBitMaskEnum {
>       rsbmIsTransport    = 0x0040,
>       rsbmIsWritePending = 0x0080
>     };
>     typedef StateBitMask ResipStateBitMask;
>
>    private:
>
>     static
>     int
>     compare(const Poll::FDEntry * leftFDEntry,
>             const Poll::FDEntry * rightFDEntry);
>
>     // Fields:
>     Poll *                       _poll;
>     int/*FD*/                    _fd;
>     Poll::FDEntry::StateBitMask  _stateBitMask;
>     unsigned short               _index; // Within
> "_poll->_fdEntryVector".
>
>    public:
>
>     //constructor
>     FDEntry(Poll *     poll,
>             bool       isTransport,
>             int/*FD*/  fd);
>
>     //destructor
>     ~FDEntry();
>
>     inline
>     int//FD
>     getFD() const
>     {
>       return _fd;
>     }
>
>     inline
>     Poll::FDEntry::StateBitMask
>     getStateBitMask() const
>     {
>       return _stateBitMask;
>     }
>
>     void
>     clearFDState();
>
>    protected:
>
>     void
>     setIsWritePending(bool isWritePending);
>
>    private:
>
>     // Copy constructor: declared but not defined
>     FDEntry(const Poll::FDEntry &  from);
>
>     // Assignment: declared but not defined
>     Poll::FDEntry &
>     operator=(const Poll::FDEntry &  from);
>
>   };
>   friend class Poll::FDEntry;
>
>  private:
>
>   // Fields:
>   vector<Poll::FDEntry *>          _fdEntryVector;
> #ifdef RESIP_POLL_IMPL_POLL
>   vector<pollfd>                   _pollFDVector;
> #endif
> #ifdef RESIP_POLL_IMPL_SELECT
>   int/*FD*/                        _maxFDPlus1;
>   fd_set                           _readFDSet;
>   fd_set                           _writeFDSet;
> #endif
> #ifdef RESIP_POLL_EXTERN
>   map<int/*FD*/, Poll::FDEntry *>  _fdEntryMap;
> #endif
>   vector<Poll::FDEntry *>          _waitResult;
>
>  public:
>
>   /*
>   "waitResult" is the result of method "wait" or "afterExternWait".
>   Returns the index of the entry with the smallest file
> descriptor >= "fd" in
>   "waitResult", or "waitResult.size()" if none exists.
>   */
>   static
>   int
>   findFDInWaitResult(int/*FD*/                        fd,
>                      const vector<Poll::FDEntry *> &  waitResult);
>
>   //constructor
>   Poll();
>
>   //destructor
>   ~Poll();
>
> #ifdef RESIP_POLL_EXTERN  // {
>
>   // The result is the set of entries in this poll object.
>   const vector<Poll::FDEntry *> &
>   beforeExternWait();
>
>   /*
>   If "fd" has no entry in this poll object, ignore it and return false.
>   Otherwise, set the entry's FD state from "fdStateBitMask" and
> return true.
>   If the same "fd" is passed in multiple times, the "fdStateBitMask" are
>   or-ed together.
>   */
>   bool
>   setEntryFDStateForExternWait(int/*FD*/                    fd,
>                                Poll::FDEntry::StateBitMask
> fdStateBitMask);
>
>   // The result is identical to that of method "wait".
>   const vector<Poll::FDEntry *> &
>   afterExternWait();
>
> #else //!defined(RESIP_POLL_EXTERN)  } {
>
>   /*
>   Wait for I/O on any of this poll object's entry's file descriptors.
>   More precisely, wait for the file descriptor of any entry with a pending
>   write to be writable or for any entry's file descriptor to have readable
>   input or an error.
>   If "timeoutMilliSeconds" is negative, it means wait
> indefinitely, otherwise
>   it indicates the maximum period to wait.
>   The result is an array of the entries for the file descriptors that are
>   readable, writable, or error, as specified by each entry's FD state.
>   The result contains no duplicates and is sorted by file descriptor.
>   (To service file descriptors with round-robin prioritization,
> remember the
>   last file descriptor serviced and use method
> "Poll::findFDInWaitResult" to
>   find the index in the result array of the highest priority entry.)
>   The result is valid until the next call to this method, method
>   "beforeExternWait", or the destructor.
>   At some point before then, for each entry in the result, method
>   "Poll::FDEntry::clearFDState" must be called.
>   */
>   const vector<Poll::FDEntry *> &
>   wait(int timeoutMilliSeconds);
>
> #endif //!defined(RESIP_POLL_EXTERN)  }
>
>  private:
>
>   // Copy constructor: declared but not defined
>   Poll(const Poll &  from);
>
>   // Assignment: declared but not defined
>   Poll &
>   operator=(const Poll &  from);
>
> };
>
> //////////////////////////////////////////////////////////////////
> /////////////
>
> } // namespace resip
>
> #endif //!defined(RESIP_POLL_HXX)
> ################################################################
>
>
> -------------------------------------------------------
> This SF.Net email sponsored by: ApacheCon 2003,
> 16-19 November in Las Vegas. Learn firsthand the latest
> developments in Apache, PHP, Perl, XML, Java, MySQL,
> WebDAV, and more! http://www.apachecon.com/
> _______________________________________________
> Resiprocate-devel mailing list
> Resiprocate-devel@xxxxxxxxxxxxxxxxxxxxx
> https://lists.sourceforge.net/lists/listinfo/resiprocate-devel
>