diff options
Diffstat (limited to 'src/vpp-api/python/pneum/pneum.c')
-rw-r--r-- | src/vpp-api/python/pneum/pneum.c | 467 |
1 files changed, 0 insertions, 467 deletions
diff --git a/src/vpp-api/python/pneum/pneum.c b/src/vpp-api/python/pneum/pneum.c deleted file mode 100644 index da9d69dfd4f..00000000000 --- a/src/vpp-api/python/pneum/pneum.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <netinet/in.h> -#include <netdb.h> -#include <signal.h> -#include <stdbool.h> -#include <vnet/vnet.h> -#include <vlib/vlib.h> -#include <vlib/unix/unix.h> -#include <vlibapi/api.h> -#include <vlibmemory/api.h> - -#include <vpp/api/vpe_msg_enum.h> - -#include "pneum.h" - -/* - * Asynchronous mode: - * Client registers a callback. All messages are sent to the callback. - * Synchronous mode: - * Client calls blocking read(). - * Clients are expected to collate events on a queue. - * pneum_write() -> suspends RX thread - * pneum_read() -> resumes RX thread - */ - -#define vl_typedefs /* define message structures */ -#include <vpp/api/vpe_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include <vpp/api/vpe_all_api_h.h> -#undef vl_endianfun - -vlib_main_t vlib_global_main; -vlib_main_t **vlib_mains; - -typedef struct { - u8 connected_to_vlib; - pthread_t rx_thread_handle; - pthread_t timeout_thread_handle; - pthread_mutex_t queue_lock; - pthread_cond_t suspend_cv; - pthread_cond_t resume_cv; - pthread_mutex_t timeout_lock; - pthread_cond_t timeout_cv; - pthread_cond_t timeout_cancel_cv; - pthread_cond_t terminate_cv; -} pneum_main_t; - -pneum_main_t pneum_main; -pneum_callback_t pneum_callback; -u16 read_timeout = 0; -bool rx_is_running = false; - -static void -init (void) -{ - pneum_main_t *pm = &pneum_main; - memset(pm, 0, sizeof(*pm)); - pthread_mutex_init(&pm->queue_lock, NULL); - pthread_cond_init(&pm->suspend_cv, NULL); - pthread_cond_init(&pm->resume_cv, NULL); - pthread_mutex_init(&pm->timeout_lock, NULL); - pthread_cond_init(&pm->timeout_cv, NULL); - pthread_cond_init(&pm->timeout_cancel_cv, NULL); - pthread_cond_init(&pm->terminate_cv, NULL); -} - -static void -cleanup (void) -{ - pneum_main_t *pm = &pneum_main; - pthread_cond_destroy(&pm->suspend_cv); - pthread_cond_destroy(&pm->resume_cv); - pthread_cond_destroy(&pm->timeout_cv); - pthread_cond_destroy(&pm->timeout_cancel_cv); - pthread_cond_destroy(&pm->terminate_cv); - pthread_mutex_destroy(&pm->queue_lock); - pthread_mutex_destroy(&pm->timeout_lock); - memset (pm, 0, sizeof (*pm)); -} - -/* - * Satisfy external references when -lvlib is not available. - */ -void vlib_cli_output (struct vlib_main_t * vm, char * fmt, ...) -{ - clib_warning ("vlib_cli_output called..."); -} - -void -pneum_free (void * msg) -{ - vl_msg_api_free (msg); -} - -static void -pneum_api_handler (void *msg) -{ - u16 id = ntohs(*((u16 *)msg)); - msgbuf_t *msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data)); - int l = ntohl(msgbuf->data_len); - if (l == 0) - clib_warning("Message ID %d has wrong length: %d\n", id, l); - - /* Call Python callback */ - ASSERT(pneum_callback); - (pneum_callback)(msg, l); - pneum_free(msg); -} - -static void * -pneum_rx_thread_fn (void *arg) -{ - unix_shared_memory_queue_t *q; - pneum_main_t *pm = &pneum_main; - api_main_t *am = &api_main; - uword msg; - - q = am->vl_input_queue; - - while (1) - while (!unix_shared_memory_queue_sub(q, (u8 *)&msg, 0)) - { - u16 id = ntohs(*((u16 *)msg)); - switch (id) { - case VL_API_RX_THREAD_EXIT: - vl_msg_api_free((void *) msg); - /* signal waiting threads that this thread is about to terminate */ - pthread_mutex_lock(&pm->queue_lock); - pthread_cond_signal(&pm->terminate_cv); - pthread_mutex_unlock(&pm->queue_lock); - pthread_exit(0); - return 0; - break; - - case VL_API_MEMCLNT_RX_THREAD_SUSPEND: - vl_msg_api_free((void * )msg); - /* Suspend thread and signal reader */ - pthread_mutex_lock(&pm->queue_lock); - pthread_cond_signal(&pm->suspend_cv); - /* Wait for the resume signal */ - pthread_cond_wait (&pm->resume_cv, &pm->queue_lock); - pthread_mutex_unlock(&pm->queue_lock); - break; - - case VL_API_MEMCLNT_READ_TIMEOUT: - clib_warning("Received read timeout in async thread\n"); - vl_msg_api_free((void *) msg); - break; - - default: - pneum_api_handler((void *)msg); - } - } -} - -static void * -pneum_timeout_thread_fn (void *arg) -{ - vl_api_memclnt_read_timeout_t *ep; - pneum_main_t *pm = &pneum_main; - api_main_t *am = &api_main; - struct timespec ts; - struct timeval tv; - u16 timeout; - int rv; - - while (1) - { - /* Wait for poke */ - pthread_mutex_lock(&pm->timeout_lock); - pthread_cond_wait (&pm->timeout_cv, &pm->timeout_lock); - timeout = read_timeout; - gettimeofday(&tv, NULL); - ts.tv_sec = tv.tv_sec + timeout; - ts.tv_nsec = 0; - rv = pthread_cond_timedwait (&pm->timeout_cancel_cv, - &pm->timeout_lock, &ts); - pthread_mutex_unlock(&pm->timeout_lock); - if (rv == ETIMEDOUT) - { - ep = vl_msg_api_alloc (sizeof (*ep)); - ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_READ_TIMEOUT); - vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep); - } - } - pthread_exit(0); -} - -void -pneum_rx_suspend (void) -{ - api_main_t *am = &api_main; - pneum_main_t *pm = &pneum_main; - vl_api_memclnt_rx_thread_suspend_t *ep; - - if (!pm->rx_thread_handle) return; - pthread_mutex_lock(&pm->queue_lock); - if (rx_is_running) - { - ep = vl_msg_api_alloc (sizeof (*ep)); - ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_RX_THREAD_SUSPEND); - vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep); - /* Wait for RX thread to tell us it has suspendend */ - pthread_cond_wait(&pm->suspend_cv, &pm->queue_lock); - rx_is_running = false; - } - pthread_mutex_unlock(&pm->queue_lock); -} - -void -pneum_rx_resume (void) -{ - pneum_main_t *pm = &pneum_main; - if (!pm->rx_thread_handle) return; - pthread_mutex_lock(&pm->queue_lock); - if (rx_is_running) return; - pthread_cond_signal(&pm->resume_cv); - rx_is_running = true; - pthread_mutex_unlock(&pm->queue_lock); -} - -uword * -pneum_msg_table_get_hash (void) -{ - api_main_t *am = &api_main; - return (am->msg_index_by_name_and_crc); -} - -int -pneum_msg_table_size(void) -{ - api_main_t *am = &api_main; - return hash_elts(am->msg_index_by_name_and_crc); -} - -int -pneum_connect (char * name, char * chroot_prefix, pneum_callback_t cb, - int rx_qlen) -{ - int rv = 0; - pneum_main_t *pm = &pneum_main; - - init(); - if (chroot_prefix != NULL) - vl_set_memory_root_path (chroot_prefix); - - if ((rv = vl_client_api_map("/vpe-api"))) { - clib_warning ("vl_client_api map rv %d", rv); - return rv; - } - - if (vl_client_connect(name, 0, rx_qlen) < 0) { - vl_client_api_unmap(); - return (-1); - } - - if (cb) { - /* Start the rx queue thread */ - rv = pthread_create(&pm->rx_thread_handle, NULL, pneum_rx_thread_fn, 0); - if (rv) { - clib_warning("pthread_create returned %d", rv); - vl_client_api_unmap(); - return (-1); - } - pneum_callback = cb; - rx_is_running = true; - } - - /* Start read timeout thread */ - rv = pthread_create(&pm->timeout_thread_handle, NULL, - pneum_timeout_thread_fn, 0); - if (rv) { - clib_warning("pthread_create returned %d", rv); - vl_client_api_unmap(); - return (-1); - } - - pm->connected_to_vlib = 1; - - return (0); -} - -int -pneum_disconnect (void) -{ - api_main_t *am = &api_main; - pneum_main_t *pm = &pneum_main; - - if (!pm->connected_to_vlib) return 0; - - if (pm->rx_thread_handle) { - vl_api_rx_thread_exit_t *ep; - uword junk; - ep = vl_msg_api_alloc (sizeof (*ep)); - ep->_vl_msg_id = ntohs(VL_API_RX_THREAD_EXIT); - vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep); - - /* wait (with timeout) until RX thread has finished */ - struct timespec ts; - struct timeval tv; - gettimeofday(&tv, NULL); - ts.tv_sec = tv.tv_sec + 5; - ts.tv_nsec = 0; - pthread_mutex_lock(&pm->queue_lock); - int rv = pthread_cond_timedwait(&pm->terminate_cv, &pm->queue_lock, &ts); - pthread_mutex_unlock(&pm->queue_lock); - /* now join so we wait until thread has -really- finished */ - if (rv == ETIMEDOUT) - pthread_cancel(pm->rx_thread_handle); - else - pthread_join(pm->rx_thread_handle, (void **) &junk); - } - if (pm->timeout_thread_handle) - pthread_cancel(pm->timeout_thread_handle); - - vl_client_disconnect(); - vl_client_api_unmap(); - pneum_callback = 0; - - cleanup(); - - return (0); -} - -static void -set_timeout (unsigned short timeout) -{ - pneum_main_t *pm = &pneum_main; - pthread_mutex_lock(&pm->timeout_lock); - read_timeout = timeout; - pthread_cond_signal(&pm->timeout_cv); - pthread_mutex_unlock(&pm->timeout_lock); -} - -static void -unset_timeout (void) -{ - pneum_main_t *pm = &pneum_main; - pthread_mutex_lock(&pm->timeout_lock); - pthread_cond_signal(&pm->timeout_cancel_cv); - pthread_mutex_unlock(&pm->timeout_lock); -} - -int -pneum_read (char **p, int *l, u16 timeout) -{ - unix_shared_memory_queue_t *q; - api_main_t *am = &api_main; - pneum_main_t *pm = &pneum_main; - uword msg; - msgbuf_t *msgbuf; - - if (!pm->connected_to_vlib) return -1; - - *l = 0; - - if (am->our_pid == 0) return (-1); - - /* Poke timeout thread */ - if (timeout) - set_timeout(timeout); - - q = am->vl_input_queue; - int rv = unix_shared_memory_queue_sub(q, (u8 *)&msg, 0); - if (rv == 0) { - u16 msg_id = ntohs(*((u16 *)msg)); - switch (msg_id) { - case VL_API_RX_THREAD_EXIT: - printf("Received thread exit\n"); - return -1; - case VL_API_MEMCLNT_RX_THREAD_SUSPEND: - printf("Received thread suspend\n"); - goto error; - case VL_API_MEMCLNT_READ_TIMEOUT: - printf("Received read timeout %ds\n", timeout); - goto error; - - default: - msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data)); - *l = ntohl(msgbuf->data_len); - if (*l == 0) { - printf("Unregistered API message: %d\n", msg_id); - goto error; - } - } - *p = (char *)msg; - - /* Let timeout notification thread know we're done */ - unset_timeout(); - - } else { - printf("Read failed with %d\n", rv); - } - return (rv); - - error: - vl_msg_api_free((void *) msg); - /* Client might forget to resume RX thread on failure */ - pneum_rx_resume (); - return -1; -} - -/* - * XXX: Makes the assumption that client_index is the first member - */ -typedef VL_API_PACKED(struct _vl_api_header { - u16 _vl_msg_id; - u32 client_index; -}) vl_api_header_t; - -static unsigned int -pneum_client_index (void) -{ - return (api_main.my_client_index); -} - -int -pneum_write (char *p, int l) -{ - int rv = -1; - api_main_t *am = &api_main; - vl_api_header_t *mp = vl_msg_api_alloc(l); - unix_shared_memory_queue_t *q; - pneum_main_t *pm = &pneum_main; - - if (!pm->connected_to_vlib) return -1; - if (!mp) return (-1); - - memcpy(mp, p, l); - mp->client_index = pneum_client_index(); - q = am->shmem_hdr->vl_input_queue; - rv = unix_shared_memory_queue_add(q, (u8 *)&mp, 0); - if (rv != 0) { - clib_warning("vpe_api_write fails: %d\n", rv); - /* Clear message */ - pneum_free(mp); - } - return (rv); -} - -uint32_t -pneum_get_msg_index (unsigned char * name) -{ - return vl_api_get_msg_index (name); -} |