zmq.Ctx Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jeromq Show documentation
Show all versions of jeromq Show documentation
Pure Java implementation of libzmq
/*
Copyright (c) 2007-2012 iMatix Corporation
Copyright (c) 2009-2011 250bpm s.r.o.
Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser 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
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//Context object encapsulates all the global state associated with
// the library.
public class Ctx {
// Information associated with inproc endpoint. Note that endpoint options
// are registered as well so that the peer can access them without a need
// for synchronisation, handshaking or similar.
public static class Endpoint {
SocketBase socket;
Options options;
public Endpoint(SocketBase socket_, Options options_) {
socket = socket_;
options = options_;
}
}
// Used to check whether the object is a context.
private int tag;
// Sockets belonging to this context. We need the list so that
// we can notify the sockets when zmq_term() is called. The sockets
// will return ETERM then.
private final List sockets;
// List of unused thread slots.
private final Deque empty_slots;
// If true, zmq_init has been called but no socket has been created
// yet. Launching of I/O threads is delayed.
private AtomicBoolean starting = new AtomicBoolean(true);
// If true, zmq_term was already called.
private boolean terminating;
// Synchronisation of accesses to global slot-related data:
// sockets, empty_slots, terminating. It also synchronises
// access to zombie sockets as such (as opposed to slots) and provides
// a memory barrier to ensure that all CPU cores see the same data.
private final Lock slot_sync;
// The reaper thread.
private Reaper reaper;
// I/O threads.
private final List io_threads;
// Array of pointers to mailboxes for both application and I/O threads.
private int slot_count;
private Mailbox[] slots;
// Mailbox for zmq_term thread.
private final Mailbox term_mailbox;
// List of inproc endpoints within this context.
private final Map endpoints;
// Synchronisation of access to the list of inproc endpoints.
private final Lock endpoints_sync;
// Maximum socket ID.
private static AtomicInteger max_socket_id = new AtomicInteger(0);
// Maximum number of sockets that can be opened at the same time.
private int max_sockets;
// Number of I/O threads to launch.
private int io_thread_count;
// Synchronisation of access to context options.
private final Lock opt_sync;
public static final int term_tid = 0;
public static final int reaper_tid = 1;
public Ctx ()
{
tag = 0xabadcafe;
terminating = false;
reaper = null;
slot_count = 0;
slots = null;
max_sockets = ZMQ.ZMQ_MAX_SOCKETS_DFLT;
io_thread_count = ZMQ.ZMQ_IO_THREADS_DFLT;
slot_sync = new ReentrantLock();
endpoints_sync = new ReentrantLock();
opt_sync = new ReentrantLock();
term_mailbox = new Mailbox("terminater");
empty_slots = new ArrayDeque();
io_threads = new ArrayList();
sockets = new ArrayList();
endpoints = new HashMap();
}
protected void destroy() {
for (IOThread it: io_threads) {
it.stop();
}
for (IOThread it: io_threads) {
it.destroy();
}
if (reaper != null)
reaper.destroy();
term_mailbox.close();
tag = 0xdeadbeef;
}
// Returns false if object is not a context.
public boolean check_tag ()
{
return tag == 0xabadcafe;
}
// 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
// down. If there are open sockets still, the deallocation happens
// after the last one is closed.
public void terminate() {
tag = 0xdeadbeef;
if (!starting.get()) {
slot_sync.lock ();
try {
// Check whether termination was already underway, but interrupted and now
// restarted.
boolean restarted = terminating;
terminating = true;
// First attempt to terminate the context.
if (!restarted) {
// First send stop command to sockets so that any blocking calls
// can be interrupted. If there are no sockets we can ask reaper
// thread to stop.
for (int i = 0; i != sockets.size (); i++)
sockets.get(i).stop ();
if (sockets.isEmpty ())
reaper.stop ();
}
} finally {
slot_sync.unlock();
}
// Wait till reaper thread closes all the sockets.
Command cmd = term_mailbox.recv (-1);
if (cmd == null)
throw new IllegalStateException();
assert (cmd.type() == Command.Type.DONE);
slot_sync.lock ();
try {
assert (sockets.isEmpty ());
} finally {
slot_sync.unlock ();
}
}
// Deallocate the resources.
destroy();
}
public boolean set (int option_, int optval_)
{
if (option_ == ZMQ.ZMQ_MAX_SOCKETS && optval_ >= 1) {
opt_sync.lock ();
try {
max_sockets = optval_;
} finally {
opt_sync.unlock ();
}
}
else
if (option_ == ZMQ.ZMQ_IO_THREADS && optval_ >= 0) {
opt_sync.lock ();
try {
io_thread_count = optval_;
} finally {
opt_sync.unlock ();
}
}
else {
return false;
}
return true;
}
public int get (int option_)
{
int rc = 0;
if (option_ == ZMQ.ZMQ_MAX_SOCKETS)
rc = max_sockets;
else
if (option_ == ZMQ.ZMQ_IO_THREADS)
rc = io_thread_count;
else {
throw new IllegalArgumentException("option = " + option_);
}
return rc;
}
public SocketBase create_socket (int type_)
{
SocketBase s = null;
slot_sync.lock ();
try {
if (starting.compareAndSet(true, false)) {
// Initialise the array of mailboxes. Additional three slots are for
// zmq_term thread and reaper thread.
int mazmq;
int ios;
opt_sync.lock ();
try {
mazmq = max_sockets;
ios = io_thread_count;
} finally {
opt_sync.unlock ();
}
slot_count = mazmq + ios + 2;
slots = new Mailbox[slot_count];
//alloc_assert (slots);
// Initialise the infrastructure for zmq_term thread.
slots [term_tid] = term_mailbox;
// Create the reaper thread.
reaper = new Reaper (this, reaper_tid);
//alloc_assert (reaper);
slots [reaper_tid] = reaper.get_mailbox ();
reaper.start ();
// Create I/O thread objects and launch them.
for (int i = 2; i != ios + 2; i++) {
IOThread io_thread = new IOThread (this, i);
//alloc_assert (io_thread);
io_threads.add(io_thread);
slots [i] = io_thread.get_mailbox ();
io_thread.start ();
}
// In the unused part of the slot array, create a list of empty slots.
for (int i = (int) slot_count - 1;
i >= (int) ios + 2; i--) {
empty_slots.add (i);
slots [i] = null;
}
}
// Once zmq_term() was called, we can't create new sockets.
if (terminating) {
throw new ZError.CtxTerminatedException();
}
// If max_sockets limit was reached, return error.
if (empty_slots.isEmpty ()) {
throw new IllegalStateException("EMFILE");
}
// Choose a slot for the socket.
int slot = empty_slots.pollLast();
// Generate new unique socket ID.
int sid = max_socket_id.incrementAndGet();
// Create the socket and register its mailbox.
s = SocketBase.create (type_, this, slot, sid);
if (s == null) {
empty_slots.addLast(slot);
return null;
}
sockets.add (s);
slots [slot] = s.get_mailbox ();
} finally {
slot_sync.unlock ();
}
return s;
}
public void destroy_socket(SocketBase socket_) {
slot_sync.lock ();
// Free the associated thread slot.
try {
int tid = socket_.get_tid ();
empty_slots.add (tid);
slots [tid].close();
slots [tid] = null;
// Remove the socket from the list of sockets.
sockets.remove (socket_);
// If zmq_term() was already called and there are no more socket
// we can ask reaper thread to terminate.
if (terminating && sockets.isEmpty ())
reaper.stop ();
} finally {
slot_sync.unlock ();
}
}
// Returns reaper thread object.
public ZObject get_reaper() {
return reaper;
}
// Send command to the destination thread.
public void send_command (int tid_, final Command command_)
{
slots [tid_].send (command_);
}
// Returns the I/O thread that is the least busy at the moment.
// Affinity specifies which I/O threads are eligible (0 = all).
// Returns NULL if no I/O thread is available.
public IOThread choose_io_thread(long affinity_) {
if (io_threads.isEmpty ())
return null;
// Find the I/O thread with minimum load.
int min_load = -1;
IOThread selected_io_thread = null;
for (int i = 0; i != io_threads.size (); i++) {
if (affinity_ == 0 || (affinity_ & ( 1L << i)) > 0) {
int load = io_threads .get(i).get_load ();
if (selected_io_thread == null || load < min_load) {
min_load = load;
selected_io_thread = io_threads.get(i);
}
}
}
return selected_io_thread;
}
// Management of inproc endpoints.
public boolean register_endpoint(String addr_, Endpoint endpoint_) {
endpoints_sync.lock ();
Endpoint inserted = null;
try {
inserted = endpoints.put(addr_, endpoint_);
} finally {
endpoints_sync.unlock ();
}
if (inserted != null) {
return false;
}
return true;
}
public void unregister_endpoints(SocketBase socket_) {
endpoints_sync.lock ();
try {
Iterator> it = endpoints.entrySet().iterator();
while (it.hasNext()) {
Entry e = it.next();
if (e.getValue().socket == socket_) {
it.remove();
continue;
}
}
} finally {
endpoints_sync.unlock ();
}
}
public Endpoint find_endpoint (String addr_)
{
Endpoint endpoint = null;
endpoints_sync.lock ();
try {
endpoint = endpoints.get(addr_);
if (endpoint == null) {
//ZError.errno(ZError.ECONNREFUSED);
return new Endpoint(null, new Options());
}
// Increment the command sequence number of the peer so that it won't
// get deallocated until "bind" command is issued by the caller.
// The subsequent 'bind' has to be called with inc_seqnum parameter
// set to false, so that the seqnum isn't incremented twice.
endpoint.socket.inc_seqnum ();
} finally {
endpoints_sync.unlock ();
}
return endpoint;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy