int flux_event_unsubscribe (flux_t h, const char *topic) { if (h->ops->event_unsubscribe) { if (h->ops->event_unsubscribe (h->impl, topic) < 0) goto fatal; } return 0; fatal: FLUX_FATAL (h); return -1; }
int flux_send (flux_t h, const flux_msg_t *msg, int flags) { if (!h->ops->send) { errno = ENOSYS; goto fatal; } flags |= h->flags; update_tx_stats (h, msg); if (flags & FLUX_O_TRACE) flux_msg_fprint (stderr, msg); if (h->ops->send (h->impl, msg, flags) < 0) goto fatal; #if HAVE_CALIPER profiling_msg_snapshot(h, msg, flags, "send"); #endif return 0; fatal: FLUX_FATAL (h); return -1; }
/* FIXME: FLUX_O_TRACE will show these messages being received again * So will message counters. */ int flux_requeue (flux_t h, const flux_msg_t *msg, int flags) { flux_msg_t *cpy; int rc; if (flags != FLUX_RQ_TAIL && flags != FLUX_RQ_HEAD) { errno = EINVAL; goto fatal; } if (!(cpy = flux_msg_copy (msg, true))) goto fatal; if (flags == FLUX_RQ_TAIL) rc = msglist_append (h->queue, cpy); else rc = msglist_push (h->queue, cpy); if (rc < 0) { flux_msg_destroy (cpy); goto fatal; } return 0; fatal: FLUX_FATAL (h); return -1; }
int flux_pollfd (flux_t h) { if (h->pollfd < 0) { struct epoll_event ev = { .events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP, }; if ((h->pollfd = epoll_create1 (EPOLL_CLOEXEC)) < 0) goto fatal; /* add queue pollfd */ ev.data.fd = msglist_pollfd (h->queue); if (ev.data.fd < 0) goto fatal; if (epoll_ctl (h->pollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) goto fatal; /* add connector pollfd (if defined) */ if (h->ops->pollfd) { ev.data.fd = h->ops->pollfd (h->impl); if (ev.data.fd < 0) goto fatal; if (epoll_ctl (h->pollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) goto fatal; } } return h->pollfd; fatal: if (h->pollfd >= 0) { (void)close (h->pollfd); h->pollfd = -1; } FLUX_FATAL (h); return -1; } int flux_pollevents (flux_t h) { int e, events = 0; /* wait for handle event */ if (h->pollfd >= 0) { struct epoll_event ev; (void)epoll_wait (h->pollfd, &ev, 1, 0); } /* get connector events (if applicable) */ if (h->ops->pollevents) { if ((events = h->ops->pollevents (h->impl)) < 0) goto fatal; } /* get queue events */ if ((e = msglist_pollevents (h->queue)) < 0) goto fatal; if ((e & POLLIN)) events |= FLUX_POLLIN; if ((e & POLLOUT)) events |= FLUX_POLLOUT; if ((e & POLLERR)) events |= FLUX_POLLERR; return events; fatal: FLUX_FATAL (h); return -1; }
/* If this function is called without the NONBLOCK flag from a reactor * handler running in coprocess context, the call to flux_sleep_on() * will allow the reactor to run until a message matching 'match' arrives. * The flux_sleep_on() call will then resume, and the next call to recv() * will return the matching message. If not running in coprocess context, * flux_sleep_on() will fail with EINVAL. In that case, the do loop * reading messages and comparing them to match criteria may have to read * a few non-matching messages before finding a match. On return, those * non-matching messages have to be requeued in the handle, hence the * defer_*() helper calls. */ flux_msg_t *flux_recv (flux_t h, struct flux_match match, int flags) { zlist_t *l = NULL; flux_msg_t *msg = NULL; int saved_errno; flags |= h->flags; if (!(flags & FLUX_O_NONBLOCK) && (flags & FLUX_O_COPROC) && flux_sleep_on (h, match) < 0) { if (errno != EINVAL) goto fatal; errno = 0; } do { if (!(msg = flux_recv_any (h, flags))) { if (errno != EAGAIN && errno != EWOULDBLOCK) goto fatal; if (defer_requeue (&l, h) < 0) goto fatal; defer_destroy (&l); errno = EWOULDBLOCK; return NULL; } if (!flux_msg_cmp (msg, match)) { if (defer_enqueue (&l, msg) < 0) goto fatal; msg = NULL; } } while (!msg); update_rx_stats (h, msg); if ((flags & FLUX_O_TRACE)) flux_msg_fprint (stderr, msg); if (defer_requeue (&l, h) < 0) goto fatal; defer_destroy (&l); #if HAVE_CALIPER cali_begin_int (h->prof.msg_match_type, match.typemask); cali_begin_int (h->prof.msg_match_tag, match.matchtag); cali_begin_string (h->prof.msg_match_glob, match.topic_glob ? match.topic_glob : "NONE"); char *sender = NULL; flux_msg_get_route_first (msg, &sender); if (sender) cali_begin_string (h->prof.msg_sender, sender); profiling_msg_snapshot (h, msg, flags, "recv"); if (sender) cali_end (h->prof.msg_sender); cali_end (h->prof.msg_match_type); cali_end (h->prof.msg_match_tag); cali_end (h->prof.msg_match_glob); free (sender); #endif return msg; fatal: saved_errno = errno; FLUX_FATAL (h); if (msg) flux_msg_destroy (msg); defer_destroy (&l); errno = saved_errno; return NULL; }
static void handle_cb (flux_reactor_t *r, flux_watcher_t *hw, int revents, void *arg) { struct dispatch *d = arg; flux_msg_handler_t *w; flux_msg_t *msg = NULL; int type; if (revents & FLUX_POLLERR) goto fatal; if (!(msg = flux_recv (d->h, FLUX_MATCH_ANY, FLUX_O_NONBLOCK))) { if (errno != EAGAIN && errno != EWOULDBLOCK) goto fatal; else goto done; } if (flux_msg_get_type (msg, &type) < 0) goto done; /* Message matches a coproc that yielded. * Resume, arranging for msg to be returned next by flux_recv(). */ if ((w = find_waiting_handler (d, msg))) { if (flux_requeue (d->h, msg, FLUX_RQ_HEAD) < 0) goto fatal; zlist_remove (d->waiters, w); if (resume_coproc (w) < 0) goto fatal; /* Message matches a handler. * If coproc already running, queue message as backlog. * Else if FLUX_O_COPROC, start coproc. * If coprocs not enabled, call handler directly. */ } else if ((w = find_handler (d, msg))) { if (w->coproc && coproc_started (w->coproc)) { if (backlog_append (w, &msg) < 0) /* msg now property of backlog */ goto fatal; } else if ((flux_flags_get (d->h) & FLUX_O_COPROC)) { if (flux_requeue (d->h, msg, FLUX_RQ_HEAD) < 0) goto fatal; if (start_coproc (w) < 0) goto fatal; } else { w->fn (d->h, w, msg, w->arg); } /* Message matched nothing. * Respond with ENOSYS if it was a request. * Else log it if FLUX_O_TRACE */ } else { if (type == FLUX_MSGTYPE_REQUEST) { if (flux_respond (d->h, msg, ENOSYS, NULL)) goto done; } else if (flux_flags_get (d->h) & FLUX_O_TRACE) { const char *topic = NULL; (void)flux_msg_get_topic (msg, &topic); fprintf (stderr, "nomatch: %s '%s'\n", flux_msg_typestr (type), topic ? topic : ""); } } done: flux_msg_destroy (msg); return; fatal: flux_msg_destroy (msg); flux_reactor_stop_error (r); FLUX_FATAL (d->h); }