diff options
Diffstat (limited to 'src/vcl/vcl_event.c')
-rw-r--r-- | src/vcl/vcl_event.c | 554 |
1 files changed, 0 insertions, 554 deletions
diff --git a/src/vcl/vcl_event.c b/src/vcl/vcl_event.c deleted file mode 100644 index 38a78535ee7..00000000000 --- a/src/vcl/vcl_event.c +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright (c) 2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <vppinfra/fifo.h> -#include <vppinfra/pool.h> -#include <vppinfra/hash.h> -#include <vnet/api_errno.h> - -#include <vcl/vppcom.h> -#include <vcl/vcl_event.h> -#include <vcl/vcl_private.h> - -/** - * @file - * @brief VPP Communications Library (VCL) event handler. - * - * Definitions for generic event handling in VCL. - */ - -#define VCL_EVENTS_LOCK() \ - clib_spinlock_lock (&(vcm->event_thread.events_lockp)) -#define VCL_EVENTS_UNLOCK() \ - clib_spinlock_unlock (&(vcm->event_thread.events_lockp)) -#define VCL_IO_SESSIONS_LOCK() \ - clib_spinlock_lock (&(vcm->session_io_thread.io_sessions_lockp)) -#define VCL_IO_SESSIONS_UNLOCK() \ - clib_spinlock_unlock (&(vcm->session_io_thread.io_sessions_lockp)) - -int -vce_generate_event (vce_event_thread_t * evt, u32 ev_idx) -{ - int elts, rv = 0; - vce_event_t *p; - - pthread_mutex_lock (&(evt->generator_lock)); - - /* Check there is event data for this event */ - - VCE_EVENTS_LOCK (); - p = pool_elt_at_index (evt->vce_events, ev_idx); - ASSERT (p); - - elts = (int) clib_fifo_free_elts (evt->event_index_fifo); - if (PREDICT_TRUE (elts)) - { - /* Add event to queue */ - clib_fifo_add1 (evt->event_index_fifo, ev_idx); - pthread_cond_signal (&(evt->generator_cond)); - } - else - { - rv = VNET_API_ERROR_QUEUE_FULL; - } - - VCE_EVENTS_UNLOCK (); - pthread_mutex_unlock (&(evt->generator_lock)); - - return rv; -} - -void -vce_clear_event (vce_event_thread_t * evt, u32 ev_idx) -{ - VCE_EVENTS_LOCK (); - pool_put_index (evt->vce_events, ev_idx); - VCE_EVENTS_UNLOCK (); -} - -vce_event_t * -vce_get_event_from_index (vce_event_thread_t * evt, u32 ev_idx) -{ - vce_event_t *ev = 0; - /* Assumes caller has obtained the spinlock (evt->events_lockp) */ - - if (!pool_is_free_index (evt->vce_events, ev_idx)) - ev = pool_elt_at_index (evt->vce_events, ev_idx); - - return ev; -} - -vce_event_handler_reg_t * -vce_get_event_handler (vce_event_thread_t * evt, vce_event_key_t * evk) -{ - vce_event_handler_reg_t *handler = 0; - uword *p; - - VCE_HANDLERS_LOCK (); - p = hash_get (evt->handlers_index_by_event_key, evk->as_u64); - if (p) - handler = pool_elt_at_index (evt->vce_event_handlers, p[0]); - VCE_HANDLERS_UNLOCK (); - - return handler; -} - -vce_event_handler_reg_t * -vce_register_handler (vce_event_thread_t * evt, vce_event_key_t * evk, - vce_event_callback_t cb, void *cb_args) -{ - vce_event_handler_reg_t *handler; - vce_event_handler_reg_t *old_handler = 0; - uword *p; - u32 handler_index; - - /* TODO - multiple handler support. For now we can replace - * and re-instate, which is useful for event recycling */ - - VCE_HANDLERS_LOCK (); - - p = hash_get (evt->handlers_index_by_event_key, evk->as_u64); - if (p) - { - old_handler = pool_elt_at_index (evt->vce_event_handlers, p[0]); - /* If we are just re-registering, ignore and move on - * else store the old handler_fn for unregister to re-instate */ - if (old_handler->handler_fn == cb) - { - - VCE_HANDLERS_UNLOCK (); - - /* Signal event thread that a handler exists in case any - * recycled events requiring this handler are pending */ - pthread_mutex_lock (&(evt->generator_lock)); - pthread_cond_signal (&(evt->generator_cond)); - pthread_mutex_unlock (&(evt->generator_lock)); - return old_handler; - } - } - - pool_get (evt->vce_event_handlers, handler); - handler_index = (u32) (handler - evt->vce_event_handlers); - - handler->handler_fn = cb; - handler->replaced_handler_idx = (u32) ((p) ? p[0] : ~0); - handler->ev_idx = (u32) ~ 0; //This will be set by the event thread if event happens - handler->evk = evk->as_u64; - handler->handler_fn_args = cb_args; - - hash_set (evt->handlers_index_by_event_key, evk->as_u64, handler_index); - - pthread_cond_init (&(handler->handler_cond), NULL); - pthread_mutex_init (&(handler->handler_lock), NULL); - - VCE_HANDLERS_UNLOCK (); - - /* Signal event thread that a new handler exists in case any - * recycled events requiring this handler are pending */ - pthread_mutex_lock (&(evt->generator_lock)); - pthread_cond_signal (&(evt->generator_cond)); - pthread_mutex_unlock (&(evt->generator_lock)); - - return handler; -} - -int -vce_unregister_handler (vce_event_thread_t * evt, - vce_event_handler_reg_t * handler) -{ - uword *p; - u64 evk = handler->evk; - u8 generate_signal = 0; - - VCE_HANDLERS_LOCK (); - - p = hash_get (evt->handlers_index_by_event_key, evk); - if (!p) - { - VCE_HANDLERS_UNLOCK (); - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - handler = pool_elt_at_index (evt->vce_event_handlers, p[0]); - - /* If this handler replaced another handler, re-instate it */ - if (handler->replaced_handler_idx != ~0) - { - hash_set (evt->handlers_index_by_event_key, evk, - handler->replaced_handler_idx); - generate_signal = 1; - } - else - { - hash_unset (evt->handlers_index_by_event_key, evk); - } - - pthread_mutex_destroy (&(handler->handler_lock)); - pthread_cond_destroy (&(handler->handler_cond)); - pool_put (evt->vce_event_handlers, handler); - - VCE_HANDLERS_UNLOCK (); - - if (generate_signal) - { - /* Signal event thread that a new handler exists in case any - * recycled events requiring this handler are pending */ - pthread_mutex_lock (&(evt->generator_lock)); - pthread_cond_signal (&(evt->generator_cond)); - pthread_mutex_unlock (&(evt->generator_lock)); - } - - return 0; -} - -void * -vce_event_thread_fn (void *arg) -{ - vce_event_thread_t *evt = (vce_event_thread_t *) arg; - vce_event_t *ev; - u32 ev_idx; - vce_event_handler_reg_t *handler; - uword *p; - u32 recycle_count = 0; - - pthread_mutex_lock (&(evt->generator_lock)); - while (1) - { - uword fifo_depth = clib_fifo_elts (evt->event_index_fifo); - while ((fifo_depth == 0) || (recycle_count == fifo_depth)) - { - recycle_count = 0; - pthread_cond_wait (&(evt->generator_cond), &(evt->generator_lock)); - fifo_depth = clib_fifo_elts (evt->event_index_fifo); - } - - /* Remove event */ - VCE_EVENTS_LOCK (); - clib_fifo_sub1 (evt->event_index_fifo, ev_idx); - ev = vce_get_event_from_index (evt, ev_idx); - ASSERT (ev); - if (recycle_count && ev->recycle) - { - clib_fifo_add1 (evt->event_index_fifo, ev_idx); - VCE_EVENTS_UNLOCK (); - continue; - } - VCE_HANDLERS_LOCK (); - - p = hash_get (evt->handlers_index_by_event_key, ev->evk.as_u64); - if (!p) - { - /* If an event falls in the woods, and there is no handler to hear it, - * does it make any sound? - * I don't know either, so lets biff the event */ - pool_put (evt->vce_events, ev); - VCE_EVENTS_UNLOCK (); - VCE_HANDLERS_UNLOCK (); - pthread_mutex_unlock (&(evt->generator_lock)); - } - else - { - u32 evt_recycle = ev->recycle; - handler = pool_elt_at_index (evt->vce_event_handlers, p[0]); - handler->ev_idx = ev_idx; - ev->recycle = 0; - - VCE_EVENTS_UNLOCK (); - VCE_HANDLERS_UNLOCK (); - pthread_mutex_unlock (&(evt->generator_lock)); - - (handler->handler_fn) (handler); - - VCE_EVENTS_LOCK (); - ev = vce_get_event_from_index (evt, ev_idx); - recycle_count += (!evt_recycle && ev && ev->recycle) ? 1 : 0; - VCE_EVENTS_UNLOCK (); - } - - pthread_mutex_lock (&(evt->generator_lock)); - } - return NULL; -} - -int -vce_start_event_thread (vce_event_thread_t * evt, u8 max_events) -{ - clib_fifo_validate (evt->event_index_fifo, max_events); - evt->handlers_index_by_event_key = hash_create (0, sizeof (uword)); - - pthread_cond_init (&(evt->generator_cond), NULL); - pthread_mutex_init (&(evt->generator_lock), NULL); - - clib_spinlock_init (&(evt->events_lockp)); - clib_spinlock_init (&(evt->handlers_lockp)); - - return pthread_create (&(evt->thread), NULL /* attr */ , - vce_event_thread_fn, evt); -} - -static void * -vppcom_session_io_thread_fn (void *arg) -{ - vppcom_session_io_thread_t *evt = (vppcom_session_io_thread_t *) arg; - u32 *session_indexes = 0, *session_index; - int i; - u32 bytes = 0; - vcl_session_t *session; - - while (1) - { - vec_reset_length (session_indexes); - VCE_IO_SESSIONS_LOCK (); - /* *INDENT-OFF* */ - pool_foreach (session_index, evt->active_session_indexes, ({ - vec_add1 (session_indexes, *session_index); - })); - /* *INDENT-ON* */ - VCE_IO_SESSIONS_UNLOCK (); - if (session_indexes) - { - for (i = 0; i < vec_len (session_indexes); ++i) - { - session = vcl_session_get (0, session_indexes[i]); - if (!session) - return NULL; - bytes = svm_fifo_max_dequeue (session->rx_fifo); - - if (bytes) - { - vppcom_ioevent_t *eio; - vce_event_t *ev; - u32 ev_idx; - - VCL_EVENTS_LOCK (); - - pool_get (vcm->event_thread.vce_events, ev); - ev_idx = (u32) (ev - vcm->event_thread.vce_events); - eio = vce_get_event_data (ev, sizeof (*eio)); - ev->evk.eid = VCL_EVENT_IOEVENT_RX_FIFO; - ev->evk.session_index = session_indexes[i]; - eio->bytes = bytes; - eio->session_index = session_indexes[i]; - - VCL_EVENTS_UNLOCK (); - - vce_generate_event (&vcm->event_thread, ev_idx); - } - } - } - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = 1000000; /* 1 millisecond */ - nanosleep (&ts, NULL); - } - return NULL; -} - -static int -vppcom_start_io_event_thread (vppcom_session_io_thread_t * evt, - u8 max_sessions) -{ - pthread_cond_init (&(evt->vce_io_cond), NULL); - pthread_mutex_init (&(evt->vce_io_lock), NULL); - - clib_spinlock_init (&(evt->io_sessions_lockp)); - - return pthread_create (&(evt->thread), NULL /* attr */ , - vppcom_session_io_thread_fn, evt); -} - -static void -vce_registered_ioevent_handler_fn (void *arg) -{ - vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg; - vppcom_ioevent_t *eio; - vce_event_t *ev; - u32 ioevt_ndx = (u64) (reg->handler_fn_args); - vppcom_session_ioevent_t *ioevent, ioevent_; - - VCL_EVENTS_LOCK (); - ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx); - eio = vce_get_event_data (ev, sizeof (*eio)); - VCL_EVENTS_UNLOCK (); - - VCL_IO_SESSIONS_LOCK (); - ioevent = pool_elt_at_index (vcm->session_io_thread.ioevents, ioevt_ndx); - ioevent_ = *ioevent; - VCL_IO_SESSIONS_UNLOCK (); - (ioevent_.user_cb) (eio, ioevent_.user_cb_data); - vce_clear_event (&vcm->event_thread, reg->ev_idx); - return; - - /*TODO - Unregister check in close for this listener */ - -} - -void -vce_registered_listener_connect_handler_fn (void *arg) -{ - vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg; - vce_event_connect_request_t *ecr; - vce_event_t *ev; - vppcom_endpt_t ep; - vcl_session_t *new_session; - - vppcom_session_listener_t *session_listener = - (vppcom_session_listener_t *) reg->handler_fn_args; - - VCL_EVENTS_LOCK (); - ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx); - ecr = vce_get_event_data (ev, sizeof (*ecr)); - VCL_EVENTS_UNLOCK (); - new_session = vcl_session_get (0, ecr->accepted_session_index); - if (!new_session) - return; - - ep.is_ip4 = new_session->transport.is_ip4; - ep.port = new_session->transport.rmt_port; - if (new_session->transport.is_ip4) - clib_memcpy (&ep.ip, &new_session->transport.rmt_ip.ip4, - sizeof (ip4_address_t)); - else - clib_memcpy (&ep.ip, &new_session->transport.rmt_ip.ip6, - sizeof (ip6_address_t)); - - vppcom_send_accept_session_reply (new_session->vpp_handle, - new_session->client_context, - 0 /* retval OK */ ); - - (session_listener->user_cb) (ecr->accepted_session_index, &ep, - session_listener->user_cb_data); - - if (vcm->session_io_thread.io_sessions_lockp) - { - /* Throw this new accepted session index into the rx poll thread pool */ - VCL_IO_SESSIONS_LOCK (); - u32 *active_session_index; - pool_get (vcm->session_io_thread.active_session_indexes, - active_session_index); - *active_session_index = ecr->accepted_session_index; - VCL_IO_SESSIONS_UNLOCK (); - } - - /*TODO - Unregister check in close for this listener */ - return; - - ASSERT (0); // If we can't get a lock or accepted session fails, lets blow up. -} - -/** - * @brief vce_poll_wait_connect_request_handler_fn - * - used by vppcom_epoll_xxxx() for listener sessions - * - when a vl_api_accept_session_t_handler() generates an event - * this callback is alerted and sets the fields that vppcom_epoll_wait() - * expects to see. - * - * @param arg - void* to be cast to vce_event_handler_reg_t* - */ -void -vce_poll_wait_connect_request_handler_fn (void *arg) -{ - vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg; - vce_event_t *ev; - /* Retrieve the VCL_EVENT_CONNECT_REQ_ACCEPTED event */ - ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx); - vce_event_connect_request_t *ecr = vce_get_event_data (ev, sizeof (*ecr)); - - /* Recycling the event. */ - VCL_EVENTS_LOCK (); - ev->recycle = 1; - clib_fifo_add1 (vcm->event_thread.event_index_fifo, reg->ev_idx); - VCL_EVENTS_UNLOCK (); -} - -int -vppcom_session_register_ioevent_cb (uint32_t session_index, - vppcom_session_ioevent_cb cb, - uint8_t rx, void *ptr) -{ - int rv = VPPCOM_OK; - vce_event_key_t evk; - vppcom_session_ioevent_t *ioevent; - - if (!vcm->session_io_thread.io_sessions_lockp) - rv = vppcom_start_io_event_thread (&vcm->session_io_thread, 100); /* DAW_TODO: ??? hard-coded value */ - - if (rv == VPPCOM_OK) - { - void *io_evt_ndx; - - /* Register handler for ioevent on session_index */ - VCL_IO_SESSIONS_LOCK (); - pool_get (vcm->session_io_thread.ioevents, ioevent); - io_evt_ndx = (void *) (ioevent - vcm->session_io_thread.ioevents); - ioevent->user_cb = cb; - ioevent->user_cb_data = ptr; - VCL_IO_SESSIONS_UNLOCK (); - - evk.session_index = session_index; - evk.eid = rx ? VCL_EVENT_IOEVENT_RX_FIFO : VCL_EVENT_IOEVENT_TX_FIFO; - - (void) vce_register_handler (&vcm->event_thread, &evk, - vce_registered_ioevent_handler_fn, - io_evt_ndx); - } - return rv; -} - -int -vppcom_session_register_listener (uint32_t session_index, - vppcom_session_listener_cb cb, - vppcom_session_listener_errcb - errcb, uint8_t flags, int q_len, void *ptr) -{ - int rv = VPPCOM_OK; - vce_event_key_t evk; - vppcom_session_listener_t *listener_args; - - if (!vcm->session_io_thread.io_sessions_lockp) - rv = vppcom_start_io_event_thread (&vcm->session_io_thread, 100); /* DAW_TODO: ??? hard-coded value */ - if (rv) - { - goto done; - } - rv = vppcom_session_listen (session_index, q_len); - if (rv) - { - goto done; - } - - /* Register handler for connect_request event on listen_session_index */ - listener_args = clib_mem_alloc (sizeof (vppcom_session_listener_t)); // DAW_TODO: Use a pool instead of thrashing the memory allocator! - listener_args->user_cb = cb; - listener_args->user_cb_data = ptr; - listener_args->user_errcb = errcb; - - evk.session_index = session_index; - evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED; - (void) vce_register_handler (&vcm->event_thread, &evk, - vce_registered_listener_connect_handler_fn, - listener_args); - -done: - return rv; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ |