lock-free polling removed; ZMQ_POLL flag removed

This commit is contained in:
Martin Sustrik 2010-04-29 17:20:23 +02:00
parent 7cb076e56a
commit c193fd1466
18 changed files with 28 additions and 801 deletions

View File

@ -25,12 +25,8 @@ The 'io_threads' argument specifies the size of the 0MQ thread pool to handle
I/O operations. If your application is using 'inproc' messaging exclusively you
may set this to zero, otherwise set it to at least one.
The 'flags' argument is a combination of the flags defined below:
*ZMQ_POLL*::
Specifies that sockets within this 'context' should support multiplexing using
_zmq_poll()_. Enabling this functionality may add a small amount of latency to
message transfers compared to leaving it disabled.
There are no flags defined at the moment and the 'flags' argument should be set
to zero.
RETURN VALUE

View File

@ -144,6 +144,7 @@ ZMQ_EXPORT size_t zmq_msg_size (zmq_msg_t *msg);
/* 0MQ infrastructure (a.k.a. context) initialisation & termination. */
/******************************************************************************/
/* This flag is obsolete and has no effect. To be removed in next version. */
#define ZMQ_POLL 1
ZMQ_EXPORT void *zmq_init (int app_threads, int io_threads, int flags);

View File

@ -50,7 +50,6 @@ endif
nodist_libzmq_la_SOURCES = $(pgm_sources)
libzmq_la_SOURCES = app_thread.hpp \
atomic_bitmap.hpp \
atomic_counter.hpp \
atomic_ptr.hpp \
blob.hpp \
@ -74,7 +73,6 @@ libzmq_la_SOURCES = app_thread.hpp \
i_endpoint.hpp \
i_engine.hpp \
i_poll_events.hpp \
i_signaler.hpp \
kqueue.hpp \
lb.hpp \
likely.hpp \
@ -98,7 +96,6 @@ libzmq_la_SOURCES = app_thread.hpp \
req.hpp \
select.hpp \
session.hpp \
simple_semaphore.hpp \
socket_base.hpp \
stdint.hpp \
streamer.hpp \
@ -116,7 +113,6 @@ libzmq_la_SOURCES = app_thread.hpp \
yarray.hpp \
yarray_item.hpp \
ypipe.hpp \
ypollset.hpp \
yqueue.hpp \
zmq_connecter.hpp \
zmq_decoder.hpp \
@ -166,7 +162,6 @@ libzmq_la_SOURCES = app_thread.hpp \
uuid.cpp \
xrep.cpp \
xreq.cpp \
ypollset.cpp \
zmq.cpp \
zmq_connecter.cpp \
zmq_decoder.cpp \

View File

@ -36,7 +36,6 @@
#include "app_thread.hpp"
#include "dispatcher.hpp"
#include "fd_signaler.hpp"
#include "ypollset.hpp"
#include "err.hpp"
#include "pipe.hpp"
#include "config.hpp"
@ -59,27 +58,16 @@
#define ZMQ_DELAY_COMMANDS
#endif
zmq::app_thread_t::app_thread_t (dispatcher_t *dispatcher_, int thread_slot_,
int flags_) :
zmq::app_thread_t::app_thread_t (dispatcher_t *dispatcher_, int thread_slot_) :
object_t (dispatcher_, thread_slot_),
last_processing_time (0),
terminated (false)
{
if (flags_ & ZMQ_POLL) {
signaler = new (std::nothrow) fd_signaler_t;
zmq_assert (signaler);
}
else {
signaler = new (std::nothrow) ypollset_t;
zmq_assert (signaler);
}
}
zmq::app_thread_t::~app_thread_t ()
{
zmq_assert (sockets.empty ());
zmq_assert (signaler);
delete signaler;
}
void zmq::app_thread_t::stop ()
@ -87,16 +75,16 @@ void zmq::app_thread_t::stop ()
send_stop ();
}
zmq::i_signaler *zmq::app_thread_t::get_signaler ()
zmq::fd_signaler_t *zmq::app_thread_t::get_signaler ()
{
return signaler;
return &signaler;
}
bool zmq::app_thread_t::process_commands (bool block_, bool throttle_)
{
uint64_t signals;
if (block_)
signals = signaler->poll ();
signals = signaler.poll ();
else {
#if defined ZMQ_DELAY_COMMANDS
@ -129,7 +117,7 @@ bool zmq::app_thread_t::process_commands (bool block_, bool throttle_)
#endif
// Check whether there are any commands pending for this thread.
signals = signaler->check ();
signals = signaler.check ();
}
if (signals) {

View File

@ -25,6 +25,7 @@
#include "stdint.hpp"
#include "object.hpp"
#include "yarray.hpp"
#include "fd_signaler.hpp"
namespace zmq
{
@ -33,8 +34,7 @@ namespace zmq
{
public:
app_thread_t (class dispatcher_t *dispatcher_, int thread_slot_,
int flags_);
app_thread_t (class dispatcher_t *dispatcher_, int thread_slot_);
~app_thread_t ();
@ -43,7 +43,7 @@ namespace zmq
void stop ();
// Returns signaler associated with this application thread.
struct i_signaler *get_signaler ();
fd_signaler_t *get_signaler ();
// Processes commands sent to this thread (if any). If 'block' is
// set to true, returns only after at least one command was processed.
@ -71,7 +71,7 @@ namespace zmq
sockets_t sockets;
// App thread's signaler object.
struct i_signaler *signaler;
fd_signaler_t signaler;
// Timestamp of when commands were processed the last time.
uint64_t last_processing_time;

View File

@ -1,310 +0,0 @@
/*
Copyright (c) 2007-2010 iMatix Corporation
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ATOMIC_BITMAP_HPP_INCLUDED__
#define __ZMQ_ATOMIC_BITMAP_HPP_INCLUDED__
#include "stdint.hpp"
#include "platform.hpp"
// These are the conditions to choose between different implementations
// of atomic_bitmap.
#if defined ZMQ_FORCE_MUTEXES
#define ZMQ_ATOMIC_BITMAP_MUTEX
#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
#define ZMQ_ATOMIC_BITMAP_X86
#elif 0 && defined __sparc__ && defined __GNUC__
#define ZMQ_ATOMIC_BITMAP_SPARC
#elif defined ZMQ_HAVE_WINDOWS
#define ZMQ_ATOMIC_BITMAP_WINDOWS
#elif defined sun
#define ZMQ_ATOMIC_COUNTER_SUN
#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
#define ZMQ_ATOMIC_COUNTER_GNU
#else
#define ZMQ_ATOMIC_BITMAP_MUTEX
#endif
#if defined ZMQ_ATOMIC_BITMAP_MUTEX
#include "mutex.hpp"
#elif defined ZMQ_ATOMIC_BITMAP_WINDOWS
#include "windows.hpp"
#elif defined ZMQ_ATOMIC_BITMAP_SUN
#include <atomic.h>
#endif
namespace zmq
{
// This class encapuslates several bitwise atomic operations on unsigned
// integer. Selection of operations is driven specifically by the needs
// of ypollset implementation.
class atomic_bitmap_t
{
public:
#if (defined ZMQ_ATOMIC_BITMAP_X86 || defined ZMQ_FORCE_MUTEXES) \
&& defined __x86_64__
typedef uint64_t bitmap_t;
#else
typedef uint32_t bitmap_t;
#endif
inline atomic_bitmap_t (bitmap_t value_ = 0) :
value (value_)
{
}
inline ~atomic_bitmap_t ()
{
}
// Bit-test-set-and-reset. Sets one bit of the value and resets
// another one. Returns the original value of the reset bit.
inline bool btsr (int set_index_, int reset_index_)
{
#if defined ZMQ_ATOMIC_BITMAP_WINDOWS
while (true) {
bitmap_t oldval = value;
bitmap_t newval = (oldval | (bitmap_t (1) << set_index_)) &
~(bitmap_t (1) << reset_index_);
if (InterlockedCompareExchange ((volatile LONG*) &value, newval,
oldval) == (LONG) oldval)
return (oldval & (bitmap_t (1) << reset_index_)) ?
true : false;
}
#elif defined ZMQ_ATOMIC_BITMAP_GNU
while (true) {
bitmap_t oldval = value;
bitmap_t newval = (oldval | (bitmap_t (1) << set_index_)) &
~(bitmap_t (1) << reset_index_);
if (__sync_val_compare_and_swap (&value, oldval, newval) == oldval)
return (oldval & (bitmap_t (1) << reset_index_)) ?
true : false;
}
#elif defined ZMQ_ATOMIC_BITMAP_SUN
while (true) {
bitmap_t oldval = value;
bitmap_t newval = (oldval | (bitmap_t (1) << set_index_)) &
~(bitmap_t (1) << reset_index_);
if (atomic_cas_32 (&value, oldval, newval) == oldval)
return (oldval & (bitmap_t (1) << reset_index_)) ?
true : false;
}
#elif defined ZMQ_ATOMIC_BITMAP_X86
bitmap_t oldval, dummy;
__asm__ volatile (
"mov %0, %1\n\t"
"1:"
"mov %1, %2\n\t"
"bts %3, %2\n\t"
"btr %4, %2\n\t"
"lock cmpxchg %2, %0\n\t"
"jnz 1b\n\t"
: "+m" (value), "=&a" (oldval), "=&r" (dummy)
: "r" (bitmap_t(set_index_)), "r" (bitmap_t(reset_index_))
: "cc");
return (bool) (oldval & (bitmap_t(1) << reset_index_));
#elif defined ZMQ_ATOMIC_BITMAP_SPARC
volatile bitmap_t* valptr = &value;
bitmap_t set_val = bitmap_t(1) << set_index_;
bitmap_t reset_val = ~(bitmap_t(1) << reset_index_);
bitmap_t tmp;
bitmap_t oldval;
__asm__ volatile(
"ld [%5], %2 \n\t"
"1: \n\t"
"or %2, %0, %3 \n\t"
"and %3, %1, %3 \n\t"
"cas [%5], %2, %3 \n\t"
"cmp %2, %3 \n\t"
"bne,a,pn %%icc, 1b \n\t"
"mov %3, %2 \n\t"
: "+r" (set_val), "+r" (reset_val), "=&r" (tmp),
"=&r" (oldval), "+m" (*valptr)
: "r" (valptr)
: "cc");
return oldval;
#elif defined ZMQ_ATOMIC_BITMAP_MUTEX
sync.lock ();
bitmap_t oldval = value;
value = (oldval | (bitmap_t (1) << set_index_)) &
~(bitmap_t (1) << reset_index_);
sync.unlock ();
return (oldval & (bitmap_t (1) << reset_index_)) ? true : false;
#else
#error
#endif
}
// Sets value to newval. Returns the original value.
inline bitmap_t xchg (bitmap_t newval_)
{
bitmap_t oldval;
#if defined ZMQ_ATOMIC_BITMAP_WINDOWS
oldval = InterlockedExchange ((volatile LONG*) &value, newval_);
#elif defined ZMQ_ATOMIC_BITMAP_GNU
oldval = __sync_lock_test_and_set (&value, newval_);
#elif defined ZMQ_ATOMIC_BITMAP_SUN
oldval = atomic_swap_32 (&value, newval_);
#elif defined ZMQ_ATOMIC_BITMAP_X86
oldval = newval_;
__asm__ volatile (
"lock; xchg %0, %1"
: "=r" (oldval)
: "m" (value), "0" (oldval)
: "memory");
#elif defined ZMQ_ATOMIC_BITMAP_SPARC
oldval = value;
volatile bitmap_t* ptrin = &value;
bitmap_t tmp;
bitmap_t prev;
__asm__ __volatile__(
"ld [%4], %1\n\t"
"1:\n\t"
"mov %0, %2\n\t"
"cas [%4], %1, %2\n\t"
"cmp %1, %2\n\t"
"bne,a,pn %%icc, 1b\n\t"
"mov %2, %1\n\t"
: "+r" (newval_), "=&r" (tmp), "=&r" (prev), "+m" (*ptrin)
: "r" (ptrin)
: "cc");
return prev;
#elif defined ZMQ_ATOMIC_BITMAP_MUTEX
sync.lock ();
oldval = value;
value = newval_;
sync.unlock ();
#else
#error
#endif
return oldval;
}
// izte is "if-zero-then-else" atomic operation - if the value is zero
// it substitutes it by 'thenval' else it rewrites it by 'elseval'.
// Original value of the integer is returned from this function.
inline bitmap_t izte (bitmap_t thenval_,
bitmap_t elseval_)
{
#if defined ZMQ_ATOMIC_BITMAP_WINDOWS
while (true) {
bitmap_t oldval = value;
bitmap_t newval = oldval == 0 ? thenval_ : elseval_;
if (InterlockedCompareExchange ((volatile LONG*) &value,
newval, oldval) == (LONG) oldval)
return oldval;
}
#elif defined ZMQ_ATOMIC_BITMAP_GNU
while (true) {
bitmap_t oldval = value;
bitmap_t newval = oldval == 0 ? thenval_ : elseval_;
if (__sync_val_compare_and_swap (&value, oldval, newval) == oldval)
return oldval;
}
#elif defined ZMQ_ATOMIC_BITMAP_SUN
while (true) {
bitmap_t oldval = value;
bitmap_t newval = oldval == 0 ? thenval_ : elseval_;
if (atomic_cas_32 (&value, oldval, newval) == oldval)
return oldval;
}
#elif defined ZMQ_ATOMIC_BITMAP_X86
bitmap_t oldval;
bitmap_t dummy;
__asm__ volatile (
"mov %0, %1\n\t"
"1:"
"mov %3, %2\n\t"
"test %1, %1\n\t"
"jz 2f\n\t"
"mov %4, %2\n\t"
"2:"
"lock cmpxchg %2, %0\n\t"
"jnz 1b\n\t"
: "+m" (value), "=&a" (oldval), "=&r" (dummy)
: "r" (thenval_), "r" (elseval_)
: "cc");
return oldval;
#elif defined ZMQ_ATOMIC_BITMAP_SPARC
volatile bitmap_t* ptrin = &value;
bitmap_t tmp;
bitmap_t prev;
__asm__ __volatile__(
"ld [%3], %0 \n\t"
"mov 0, %1 \n\t"
"cas [%3], %1, %4 \n\t"
"cmp %0, %1 \n\t"
"be,a,pn %%icc,1f \n\t"
"ld [%3], %0 \n\t"
"cas [%3], %0, %5 \n\t"
"1: \n\t"
: "=&r" (tmp), "=&r" (prev), "+m" (*ptrin)
: "r" (ptrin), "r" (thenval_), "r" (elseval_)
: "cc");
return prev;
#elif defined ZMQ_ATOMIC_BITMAP_MUTEX
sync.lock ();
bitmap_t oldval = value;
value = oldval ? elseval_ : thenval_;
sync.unlock ();
return oldval;
#else
#error
#endif
}
private:
volatile bitmap_t value;
#if defined ZMQ_ATOMIC_BITMAP_MUTEX
mutex_t sync;
#endif
atomic_bitmap_t (const atomic_bitmap_t&);
void operator = (const atomic_bitmap_t&);
};
}
// Remove macros local to this file.
#if defined ZMQ_ATOMIC_BITMAP_WINDOWS
#undef ZMQ_ATOMIC_BITMAP_WINDOWS
#endif
#if defined ZMQ_ATOMIC_BITMAP_GNU
#undef ZMQ_ATOMIC_BITMAP_GNU
#endif
#if defined ZMQ_ATOMIC_BITMAP_SUN
#undef ZMQ_ATOMIC_BITMAP_SUN
#endif
#if defined ZMQ_ATOMIC_BITMAP_X86
#undef ZMQ_ATOMIC_BITMAP_X86
#endif
#if defined ZMQ_ATOMIC_BITMAP_SPARC
#undef ZMQ_ATOMIC_BITMAP_SPARC
#endif
#if defined ZMQ_ATOMIC_BITMAP_MUTEX
#undef ZMQ_ATOMIC_BITMAP_MUTEX
#endif
#endif

View File

@ -33,8 +33,7 @@
#include "windows.h"
#endif
zmq::dispatcher_t::dispatcher_t (int app_threads_, int io_threads_,
int flags_) :
zmq::dispatcher_t::dispatcher_t (int app_threads_, int io_threads_) :
sockets (0),
terminated (false)
{
@ -53,7 +52,7 @@ zmq::dispatcher_t::dispatcher_t (int app_threads_, int io_threads_,
for (int i = 0; i != app_threads_; i++) {
app_thread_info_t info;
info.associated = false;
info.app_thread = new (std::nothrow) app_thread_t (this, i, flags_);
info.app_thread = new (std::nothrow) app_thread_t (this, i);
zmq_assert (info.app_thread);
app_threads.push_back (info);
signalers.push_back (info.app_thread->get_signaler ());
@ -62,7 +61,7 @@ zmq::dispatcher_t::dispatcher_t (int app_threads_, int io_threads_,
// Create I/O thread objects.
for (int i = 0; i != io_threads_; i++) {
io_thread_t *io_thread = new (std::nothrow) io_thread_t (this,
i + app_threads_, flags_);
i + app_threads_);
zmq_assert (io_thread);
io_threads.push_back (io_thread);
signalers.push_back (io_thread->get_signaler ());

View File

@ -25,7 +25,7 @@
#include <map>
#include <string>
#include "i_signaler.hpp"
#include "fd_signaler.hpp"
#include "ypipe.hpp"
#include "command.hpp"
#include "config.hpp"
@ -51,7 +51,7 @@ namespace zmq
// Create the dispatcher object. Matrix of pipes to communicate between
// each socket and each I/O thread is created along with appropriate
// signalers.
dispatcher_t (int app_threads_, int io_threads_, int flags_);
dispatcher_t (int app_threads_, int io_threads_);
// This function is called when user invokes zmq_term. If there are
// no more sockets open it'll cause all the infrastructure to be shut
@ -125,7 +125,7 @@ namespace zmq
io_threads_t io_threads;
// Signalers for both application and I/O threads.
std::vector <i_signaler*> signalers;
std::vector <fd_signaler_t*> signalers;
// Pipe to hold the commands.
typedef ypipe_t <command_t, true,

View File

@ -21,7 +21,6 @@
#define __ZMQ_FD_SIGNALER_HPP_INCLUDED__
#include "platform.hpp"
#include "i_signaler.hpp"
#include "fd.hpp"
#include "stdint.hpp"
@ -33,7 +32,7 @@ namespace zmq
// descriptor and so it can be polled on. Same signal cannot be sent twice
// unless signals are retrieved by the reader side in the meantime.
class fd_signaler_t : public i_signaler
class fd_signaler_t
{
public:

View File

@ -1,55 +0,0 @@
/*
Copyright (c) 2007-2010 iMatix Corporation
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_SIGNALER_HPP_INCLUDED__
#define __ZMQ_I_SIGNALER_HPP_INCLUDED__
#include "stdint.hpp"
#include "fd.hpp"
namespace zmq
{
// Virtual interface used to send signals. Individual implementations
// may restrict the number of possible signal types to send.
struct i_signaler
{
virtual ~i_signaler () {};
// Send a signal with a specific ID.
virtual void signal (int signal_) = 0;
// Wait for signal. Returns a set of signals in form of a bitmap.
// Signal with index 0 corresponds to value 1, index 1 to value 2,
// index 2 to value 3 etc.
virtual uint64_t poll () = 0;
// Same as poll, however, if there is no signal available,
// function returns zero immediately instead of waiting for a signal.
virtual uint64_t check () = 0;
// Returns file descriptor that allows waiting for signals. Specific
// signalers may not support this functionality. If so, the function
// returns retired_fd.
virtual fd_t get_fd () = 0;
};
}
#endif

View File

@ -27,10 +27,8 @@
#include "err.hpp"
#include "command.hpp"
#include "dispatcher.hpp"
#include "simple_semaphore.hpp"
zmq::io_thread_t::io_thread_t (dispatcher_t *dispatcher_, int thread_slot_,
int flags_) :
zmq::io_thread_t::io_thread_t (dispatcher_t *dispatcher_, int thread_slot_) :
object_t (dispatcher_, thread_slot_)
{
poller = new (std::nothrow) poller_t;
@ -56,7 +54,7 @@ void zmq::io_thread_t::stop ()
send_stop ();
}
zmq::i_signaler *zmq::io_thread_t::get_signaler ()
zmq::fd_signaler_t *zmq::io_thread_t::get_signaler ()
{
return &signaler;
}

View File

@ -38,8 +38,7 @@ namespace zmq
{
public:
io_thread_t (class dispatcher_t *dispatcher_, int thread_slot_,
int flags_);
io_thread_t (class dispatcher_t *dispatcher_, int thread_slot_);
// Clean-up. If the thread was started, it's neccessary to call 'stop'
// before invoking destructor. Otherwise the destructor would hang up.
@ -52,7 +51,7 @@ namespace zmq
void stop ();
// Returns signaler associated with this I/O thread.
i_signaler *get_signaler ();
fd_signaler_t *get_signaler ();
// i_poll_events implementation.
void in_event ();

View File

@ -24,7 +24,6 @@
#include "err.hpp"
#include "pipe.hpp"
#include "io_thread.hpp"
#include "simple_semaphore.hpp"
#include "owned.hpp"
#include "session.hpp"
#include "socket_base.hpp"

View File

@ -51,8 +51,9 @@ int zmq::queue (class socket_base_t *insocket_,
errno_assert (rc > 0);
// The algorithm below asumes ratio of request and replies processed
// under full load to be 1:1. The alternative would be to process
// replies first, handle request only when there are no more replies.
// under full load to be 1:1. While processing requests replies first
// is tempting it is suspectible to DoS attacks (overloading the system
// with unsolicited replies).
// Receive a new request.
if (items [0].revents & ZMQ_POLLIN) {

View File

@ -1,242 +0,0 @@
/*
Copyright (c) 2007-2010 iMatix Corporation
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_SIMPLE_SEMAPHORE_HPP_INCLUDED__
#define __ZMQ_SIMPLE_SEMAPHORE_HPP_INCLUDED__
#include "platform.hpp"
#include "err.hpp"
#if 0 //defined ZMQ_HAVE_LINUX
#include <sys/syscall.h>
#include <unistd.h>
#include <linux/futex.h>
#elif defined ZMQ_HAVE_LINUX ||defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_OPENVMS
#include <pthread.h>
#elif defined ZMQ_HAVE_WINDOWS
#include "windows.hpp"
#else
#include <semaphore.h>
#endif
namespace zmq
{
// Simple semaphore. Only single thread may be waiting at any given time.
// Also, the semaphore may not be posted before the previous post
// was matched by corresponding wait and the waiting thread was
// released.
#if 0 //defined ZMQ_HAVE_LINUX
// In theory, using private futexes should be more efficient on Linux
// platform than using mutexes. However, in uncontended cases of TCP
// transport on loopback interface we haven't seen any latency improvement.
// The code is commented out waiting for more thorough testing.
class simple_semaphore_t
{
public:
// Initialise the semaphore.
inline simple_semaphore_t () :
dummy (0)
{
}
// Destroy the semaphore.
inline ~simple_semaphore_t ()
{
}
// Wait for the semaphore.
inline void wait ()
{
int rc = syscall (SYS_futex, &dummy, (int) FUTEX_WAIT_PRIVATE,
(int) 0, NULL, NULL, (int) 0);
zmq_assert (rc == 0);
}
// Post the semaphore.
inline void post ()
{
while (true) {
int rc = syscall (SYS_futex, &dummy, (int) FUTEX_WAKE_PRIVATE,
(int) 1, NULL, NULL, (int) 0);
zmq_assert (rc != -1 && rc <= 1);
if (rc == 1)
break;
}
}
private:
int dummy;
// Disable copying of the object.
simple_semaphore_t (const simple_semaphore_t&);
void operator = (const simple_semaphore_t&);
};
#elif defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_OPENVMS
// On platforms that allow for double locking of a mutex from the same
// thread, simple semaphore is implemented using mutex, as it is more
// efficient than full-blown semaphore.
class simple_semaphore_t
{
public:
// Initialise the semaphore.
inline simple_semaphore_t ()
{
int rc = pthread_mutex_init (&mutex, NULL);
posix_assert (rc);
rc = pthread_mutex_lock (&mutex);
posix_assert (rc);
}
// Destroy the semaphore.
inline ~simple_semaphore_t ()
{
int rc = pthread_mutex_unlock (&mutex);
posix_assert (rc);
rc = pthread_mutex_destroy (&mutex);
posix_assert (rc);
}
// Wait for the semaphore.
inline void wait ()
{
int rc = pthread_mutex_lock (&mutex);
posix_assert (rc);
}
// Post the semaphore.
inline void post ()
{
int rc = pthread_mutex_unlock (&mutex);
posix_assert (rc);
}
private:
pthread_mutex_t mutex;
// Disable copying of the object.
simple_semaphore_t (const simple_semaphore_t&);
void operator = (const simple_semaphore_t&);
};
#elif defined ZMQ_HAVE_WINDOWS
// On Windows platform simple semaphore is implemeted using event object.
class simple_semaphore_t
{
public:
// Initialise the semaphore.
inline simple_semaphore_t ()
{
ev = CreateEvent (NULL, FALSE, FALSE, NULL);
win_assert (ev != NULL);
}
// Destroy the semaphore.
inline ~simple_semaphore_t ()
{
int rc = CloseHandle (ev);
win_assert (rc != 0);
}
// Wait for the semaphore.
inline void wait ()
{
DWORD rc = WaitForSingleObject (ev, INFINITE);
win_assert (rc != WAIT_FAILED);
}
// Post the semaphore.
inline void post ()
{
int rc = SetEvent (ev);
win_assert (rc != 0);
}
private:
HANDLE ev;
// Disable copying of the object.
simple_semaphore_t (const simple_semaphore_t&);
void operator = (const simple_semaphore_t&);
};
#else
// Default implementation maps simple semaphore to standard semaphore.
class simple_semaphore_t
{
public:
// Initialise the semaphore.
inline simple_semaphore_t ()
{
int rc = sem_init (&sem, 0, 0);
errno_assert (rc != -1);
}
// Destroy the semaphore.
inline ~simple_semaphore_t ()
{
int rc = sem_destroy (&sem);
errno_assert (rc != -1);
}
// Wait for the semaphore.
inline void wait ()
{
int rc = sem_wait (&sem);
errno_assert (rc != -1);
}
// Post the semaphore.
inline void post ()
{
int rc = sem_post (&sem);
errno_assert (rc != -1);
}
private:
// Underlying system semaphore object.
sem_t sem;
// Disable copying of the object.
simple_semaphore_t (const simple_semaphore_t&);
void operator = (const simple_semaphore_t&);
};
#endif
}
#endif

View File

@ -1,65 +0,0 @@
/*
Copyright (c) 2007-2010 iMatix Corporation
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ypollset.hpp"
zmq::ypollset_t::ypollset_t ()
{
}
zmq::ypollset_t::~ypollset_t ()
{
}
void zmq::ypollset_t::signal (int signal_)
{
zmq_assert (signal_ >= 0 && signal_ < wait_signal);
if (bits.btsr (signal_, wait_signal))
sem.post ();
}
uint64_t zmq::ypollset_t::poll ()
{
signals_t result = 0;
while (!result) {
result = bits.izte (signals_t (1) << wait_signal, 0);
if (!result) {
sem.wait ();
result = bits.xchg (0);
}
// If btsr was really atomic, result would never be 0 at this
// point, i.e. no looping would be possible. However, to
// support even CPU architectures without CAS instruction
// we allow btsr to be composed of two independent atomic
// operation (set and reset). In such case looping can occur
// sporadically.
}
return (uint64_t) result;
}
uint64_t zmq::ypollset_t::check ()
{
return (uint64_t) bits.xchg (0);
}
zmq::fd_t zmq::ypollset_t::get_fd ()
{
return retired_fd;
}

View File

@ -1,69 +0,0 @@
/*
Copyright (c) 2007-2010 iMatix Corporation
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_YPOLLSET_HPP_INCLUDED__
#define __ZMQ_YPOLLSET_HPP_INCLUDED__
#include "i_signaler.hpp"
#include "simple_semaphore.hpp"
#include "atomic_bitmap.hpp"
namespace zmq
{
// ypollset allows for rapid polling for up to constant number of
// different signals each produced by a different thread. The number of
// possible signals is platform-dependent.
class ypollset_t : public i_signaler
{
public:
ypollset_t ();
~ypollset_t ();
// i_signaler interface implementation.
void signal (int signal_);
uint64_t poll ();
uint64_t check ();
fd_t get_fd ();
private:
// Internal representation of signal bitmap.
typedef atomic_bitmap_t::bitmap_t signals_t;
// Wait signal is carried in the most significant bit of integer.
enum {wait_signal = sizeof (signals_t) * 8 - 1};
// The bits of the pollset.
atomic_bitmap_t bits;
// Used by thread waiting for signals to sleep if there are no
// signals available.
simple_semaphore_t sem;
// Disable copying of ypollset object.
ypollset_t (const ypollset_t&);
void operator = (const ypollset_t&);
};
}
#endif

View File

@ -228,14 +228,7 @@ size_t zmq_msg_size (zmq_msg_t *msg_)
void *zmq_init (int app_threads_, int io_threads_, int flags_)
{
// There should be at least a single application thread managed
// by the dispatcher. There's no need for I/O threads if 0MQ is used
// only for inproc messaging
if (app_threads_ < 1 || io_threads_ < 0 ||
app_threads_ > 63 || io_threads_ > 63) {
errno = EINVAL;
return NULL;
}
// There are no context flags defined at the moment, so flags_ is ignored.
#if defined ZMQ_HAVE_OPENPGM
// Unfortunately, OpenPGM doesn't support refcounted init/shutdown, thus,
@ -269,7 +262,7 @@ void *zmq_init (int app_threads_, int io_threads_, int flags_)
// Create 0MQ context.
zmq::dispatcher_t *dispatcher = new (std::nothrow) zmq::dispatcher_t (
app_threads_, io_threads_, flags_);
app_threads_, io_threads_);
zmq_assert (dispatcher);
return (void*) dispatcher;
}