{
fr_time_t when;
fr_channel_t *ch;
+ struct kevent events[10];
ch = talloc_zero(ctx, fr_channel_t);
if (!ch) return NULL;
ch->active = true;
+ /*
+ * Enable each individual EVFILT_USER event.
+ */
+ EV_SET(&events[0], FR_CHANNEL_SIGNAL_OPEN, EVFILT_USER, EV_ADD | EV_ONESHOT, NOTE_FFCOPY, 0, NULL);
+ EV_SET(&events[1], FR_CHANNEL_SIGNAL_CLOSE, EVFILT_USER, EV_ADD | EV_ONESHOT, NOTE_FFCOPY, 0, NULL);
+ EV_SET(&events[2], FR_CHANNEL_SIGNAL_DATA_TO_WORKER, EVFILT_USER, EV_ADD | EV_ONESHOT, NOTE_FFCOPY, 0, NULL);
+ if (kevent(kq_worker, events, 3, NULL, 0, NULL) < 0) {
+ talloc_free(ch);
+ return NULL;
+ }
+
+ /*
+ * And the same for the master KQ.
+ */
+ EV_SET(&events[0], FR_CHANNEL_SIGNAL_WORKER_SLEEPING, EVFILT_USER, EV_ADD | EV_ONESHOT, NOTE_FFCOPY, 0, NULL);
+ EV_SET(&events[1], FR_CHANNEL_SIGNAL_CLOSE, EVFILT_USER, EV_ADD | EV_ONESHOT, NOTE_FFCOPY, 0, NULL);
+ EV_SET(&events[2], FR_CHANNEL_SIGNAL_DATA_FROM_WORKER, EVFILT_USER, EV_ADD | EV_ONESHOT, NOTE_FFCOPY, 0, NULL);
+ if (kevent(kq_master, events, 3, NULL, 0, NULL) < 0) {
+ talloc_free(ch);
+ return NULL;
+ }
+
return ch;
}
* that a thread listening on multiple channels can
* receive events unique to each one.
*/
- EV_SET(&kev, which, EVFILT_USER, EV_ADD, 0, 0, ch);
+ EV_SET(&kev, which, EVFILT_USER, EV_ENABLE, NOTE_TRIGGER, 0, ch);
return kevent(end->kq, &kev, 1, NULL, 0, NULL);
}
* that a thread listening on multiple channels can
* receive events unique to each one.
*/
- EV_SET(&kev, FR_CHANNEL_SIGNAL_WORKER_SLEEPING, EVFILT_USER, EV_ADD, 0, end->ack, ch);
+ EV_SET(&kev, FR_CHANNEL_SIGNAL_WORKER_SLEEPING, EVFILT_USER, EV_ENABLE, NOTE_TRIGGER, end->ack, ch);
return kevent(end->kq, &kev, 1, NULL, 0, NULL);
}
}
/*
- * Only the master can signal that a channel should be
- * closed.
+ * Each end can signal the channel to close.
*/
if (kev->ident == FR_CHANNEL_SIGNAL_CLOSE) {
- rad_assert(kq == ch->end[TO_WORKER].kq);
+ rad_assert(kq == ch->end[kev->fflags].kq);
*p_channel = ch;
return FR_CHANNEL_CLOSE;
* - <0 on error
* - 0 on success
*/
-int fr_channel_signal_close(fr_channel_t *ch)
+int fr_channel_signal_close(fr_channel_t *ch, bool ack)
{
+ struct kevent kev;
+
ch->active = false;
- return 0;
+ EV_SET(&kev, FR_CHANNEL_SIGNAL_CLOSE, EVFILT_USER, EV_ENABLE, NOTE_TRIGGER | NOTE_FFCOPY, ack, ch);
+
+ return kevent(ch->end[ack].kq, &kev, 1, NULL, 0, NULL);
+}
+
+/** Send a channel to a KQ
+ *
+ * @param[in] kq the kqueue to send the channel
+ * @param[in] ch the channel
+ * @return
+ * - <0 on error
+ * - 0 on success
+ */
+int fr_channel_signal_open(int kq, fr_channel_t *ch)
+{
+ struct kevent kev;
+
+ rad_assert(kq == ch->end[TO_WORKER].kq);
+
+ EV_SET(&kev, FR_CHANNEL_SIGNAL_OPEN, EVFILT_USER, EV_ENABLE, NOTE_TRIGGER, 0, ch);
+
+ return kevent(kq, &kev, 1, NULL, 0, NULL);
}
#include <freeradius-devel/util/schedule.h>
#include <freeradius-devel/rbtree.h>
+#include <freeradius-devel/util/receiver.h>
+
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#define PTHREAD_MUTEX_LOCK pthread_mutex_lock
fr_worker_t *worker; //!< the worker data structure
} fr_schedule_worker_t;
+/**
+ * A data structure to track network threads / receivers.
+ */
+typedef struct fr_schedule_receiver_t {
+ pthread_t pthread_id; //!< the thread of this receiver
+
+ int kq; //!< the receivers KQ
+ fr_event_list_t *el; //!< the receivers event list
+
+ fr_receiver_t *rc; //!< the receive data structure
+} fr_schedule_receiver_t;
+
+
/**
* The scheduler
*/
}
+#if 0
+int fr_schedule_socket_add(fr_schedule_t *sc, int fd, fr_transport_t *transport, void *ctx)
+{
+ // send it to a receivers KQ as transport / ctx
+ // it receives it via the USERFILT, and adds the transport / ctx
+ // transport_ctx is largely rad_listen_t, which is a transport-specific socket
+}
+#endif
+
/*
* @todo single threaded mode. Instead of having function
* specific to single threaded mode, just fix the event loop.