diff options
Diffstat (limited to 'src/vcl/vcl_locked.c')
-rw-r--r-- | src/vcl/vcl_locked.c | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/src/vcl/vcl_locked.c b/src/vcl/vcl_locked.c new file mode 100644 index 00000000000..6254bad09b6 --- /dev/null +++ b/src/vcl/vcl_locked.c @@ -0,0 +1,457 @@ +/* + * 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 <vcl/vcl_locked.h> +#include <vcl/vcl_private.h> + +typedef struct vcl_locked_session_ +{ + u32 session_index; + u32 worker_index; + u32 vls_index; + u32 flags; + clib_spinlock_t lock; +} vcl_locked_session_t; + +typedef struct vcl_main_ +{ + vcl_locked_session_t *vls_pool; + clib_rwlock_t vls_table_lock; + uword *session_index_to_vlsh_table; +} vls_main_t; + +vls_main_t vls_main; +vls_main_t *vlsm = &vls_main; + +static inline void +vls_table_rlock (void) +{ + clib_rwlock_reader_lock (&vlsm->vls_table_lock); +} + +static inline void +vls_table_runlock (void) +{ + clib_rwlock_reader_unlock (&vlsm->vls_table_lock); +} + +static inline void +vls_table_wlock (void) +{ + clib_rwlock_writer_lock (&vlsm->vls_table_lock); +} + +static inline void +vls_table_wunlock (void) +{ + clib_rwlock_writer_unlock (&vlsm->vls_table_lock); +} + +static inline vcl_session_handle_t +vls_to_sh (vcl_locked_session_t * vls) +{ + return vppcom_session_handle (vls->session_index); +} + +static inline vcl_session_handle_t +vls_to_sh_tu (vcl_locked_session_t * vls) +{ + vcl_session_handle_t sh; + sh = vls_to_sh (vls); + vls_table_runlock (); + return sh; +} + +static vls_handle_t +vls_alloc (vcl_session_handle_t sh) +{ + vcl_locked_session_t *vls; + + vls_table_wlock (); + pool_get (vlsm->vls_pool, vls); + vls->session_index = vppcom_session_index (sh); + vls->worker_index = vppcom_session_worker (sh); + vls->vls_index = vls - vlsm->vls_pool; + hash_set (vlsm->session_index_to_vlsh_table, vls->session_index, + vls->vls_index); + clib_spinlock_init (&vls->lock); + vls_table_wunlock (); + return vls->vls_index; +} + +static vcl_locked_session_t * +vls_get (vls_handle_t vlsh) +{ + if (pool_is_free_index (vlsm->vls_pool, vlsh)) + return 0; + return pool_elt_at_index (vlsm->vls_pool, vlsh); +} + +static void +vls_free (vcl_locked_session_t * fde) +{ + ASSERT (fde != 0); + hash_unset (vlsm->session_index_to_vlsh_table, fde->session_index); + clib_spinlock_free (&fde->lock); + pool_put (vlsm->vls_pool, fde); +} + +static vcl_locked_session_t * +vls_get_and_lock (vls_handle_t vlsh) +{ + vcl_locked_session_t *vls; + if (pool_is_free_index (vlsm->vls_pool, vlsh)) + return 0; + vls = pool_elt_at_index (vlsm->vls_pool, vlsh); + clib_spinlock_lock (&vls->lock); + return vls; +} + +static vcl_locked_session_t * +vls_get_w_dlock (vls_handle_t vlsh) +{ + vcl_locked_session_t *vls; + vls_table_rlock (); + vls = vls_get_and_lock (vlsh); + if (!vls) + vls_table_runlock (); + return vls; +} + +static inline void +vls_unlock (vcl_locked_session_t * vls) +{ + clib_spinlock_unlock (&vls->lock); +} + +static inline void +vls_get_and_unlock (vls_handle_t vlsh) +{ + vcl_locked_session_t *vls; + vls_table_rlock (); + vls = vls_get (vlsh); + vls_unlock (vls); + vls_table_runlock (); +} + +static inline void +vls_dunlock (vcl_locked_session_t * vls) +{ + vls_unlock (vls); + vls_table_runlock (); +} + +static void +vls_get_and_free (vls_handle_t vlsh) +{ + vcl_locked_session_t *vls; + + vls_table_wlock (); + vls = vls_get (vlsh); + vls_free (vls); + vls_table_wunlock (); +} + +int +vls_write (vls_handle_t vlsh, void *buf, size_t nbytes) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_write (vls_to_sh_tu (vls), buf, nbytes); + vls_get_and_unlock (vlsh); + return rv; +} + +int +vls_write_msg (vls_handle_t vlsh, void *buf, size_t nbytes) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_write_msg (vls_to_sh_tu (vls), buf, nbytes); + vls_get_and_unlock (vlsh); + return rv; +} + +int +vls_sendto (vls_handle_t vlsh, void *buf, int buflen, int flags, + vppcom_endpt_t * ep) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_sendto (vls_to_sh_tu (vls), buf, buflen, flags, ep); + vls_get_and_unlock (vlsh); + return rv; +} + +ssize_t +vls_read (vls_handle_t vlsh, void *buf, size_t nbytes) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_read (vls_to_sh_tu (vls), buf, nbytes); + vls_get_and_unlock (vlsh); + return rv; +} + +ssize_t +vls_recvfrom (vls_handle_t vlsh, void *buffer, uint32_t buflen, int flags, + vppcom_endpt_t * ep) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_recvfrom (vls_to_sh_tu (vls), buffer, buflen, flags, + ep); + vls_get_and_unlock (vlsh); + return rv; +} + +int +vls_attr (vls_handle_t vlsh, uint32_t op, void *buffer, uint32_t * buflen) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_attr (vls_to_sh_tu (vls), op, buffer, buflen); + vls_get_and_unlock (vlsh); + return rv; +} + +int +vls_bind (vls_handle_t vlsh, vppcom_endpt_t * ep) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_bind (vls_to_sh_tu (vls), ep); + vls_get_and_unlock (vlsh); + return rv; +} + +int +vls_listen (vls_handle_t vlsh, int q_len) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_listen (vls_to_sh_tu (vls), q_len); + vls_get_and_unlock (vlsh); + return rv; +} + +int +vls_connect (vls_handle_t vlsh, vppcom_endpt_t * server_ep) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_session_connect (vls_to_sh_tu (vls), server_ep); + vls_get_and_unlock (vlsh); + return rv; +} + +vls_handle_t +vls_accept (vls_handle_t listener_vlsh, vppcom_endpt_t * ep, int flags) +{ + vls_handle_t accepted_vlsh; + vcl_locked_session_t *vls; + int sh; + + if (!(vls = vls_get_w_dlock (listener_vlsh))) + return VPPCOM_EBADFD; + sh = vppcom_session_accept (vls_to_sh_tu (vls), ep, flags); + vls_get_and_unlock (listener_vlsh); + if (sh < 0) + return sh; + accepted_vlsh = vls_alloc (sh); + if (PREDICT_FALSE (accepted_vlsh == VLS_INVALID_HANDLE)) + vppcom_session_close (sh); + return accepted_vlsh; +} + +vls_handle_t +vls_create (uint8_t proto, uint8_t is_nonblocking) +{ + vcl_session_handle_t sh; + vls_handle_t vlsh; + + sh = vppcom_session_create (proto, is_nonblocking); + if (sh == INVALID_SESSION_ID) + return VLS_INVALID_HANDLE; + + vlsh = vls_alloc (sh); + if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE)) + vppcom_session_close (sh); + + return vlsh; +} + +int +vls_close (vls_handle_t vlsh) +{ + vcl_locked_session_t *vls; + vcl_session_handle_t sh; + int rv, refcnt; + + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + + sh = vls_to_sh (vls); + refcnt = vppcom_session_attr (sh, VPPCOM_ATTR_GET_REFCNT, 0, 0); + if ((rv = vppcom_session_close (sh))) + { + vls_dunlock (vls); + return rv; + } + + vls_dunlock (vls); + if (refcnt <= 1) + vls_get_and_free (vlsh); + return rv; +} + +vls_handle_t +vls_epoll_create (void) +{ + vcl_session_handle_t sh; + vls_handle_t vlsh; + + sh = vppcom_epoll_create (); + if (sh == INVALID_SESSION_ID) + return VLS_INVALID_HANDLE; + + vlsh = vls_alloc (sh); + if (vlsh == VLS_INVALID_HANDLE) + vppcom_session_close (sh); + + return vlsh; +} + +int +vls_epoll_ctl (vls_handle_t ep_vlsh, int op, vls_handle_t vlsh, + struct epoll_event *event) +{ + vcl_locked_session_t *ep_vls, *vls; + vcl_session_handle_t ep_sh, sh; + int rv; + + vls_table_rlock (); + ep_vls = vls_get_and_lock (ep_vlsh); + vls = vls_get_and_lock (vlsh); + ep_sh = vls_to_sh (ep_vls); + sh = vls_to_sh (vls); + vls_table_runlock (); + + rv = vppcom_epoll_ctl (ep_sh, op, sh, event); + + vls_table_rlock (); + ep_vls = vls_get (ep_vlsh); + vls = vls_get (vlsh); + vls_unlock (vls); + vls_unlock (ep_vls); + vls_table_runlock (); + return rv; +} + +int +vls_epoll_wait (vls_handle_t ep_vlsh, struct epoll_event *events, + int maxevents, double wait_for_time) +{ + vcl_locked_session_t *vls; + int rv; + + if (!(vls = vls_get_w_dlock (ep_vlsh))) + return VPPCOM_EBADFD; + rv = vppcom_epoll_wait (vls_to_sh_tu (vls), events, maxevents, + wait_for_time); + vls_get_and_unlock (ep_vlsh); + return rv; +} + +vcl_session_handle_t +vlsh_to_sh (vls_handle_t vlsh) +{ + vcl_locked_session_t *vls; + int rv; + + vls = vls_get_w_dlock (vlsh); + if (!vls) + return INVALID_SESSION_ID; + rv = vls_to_sh (vls); + vls_dunlock (vls); + return rv; +} + +vcl_session_handle_t +vlsh_to_session_index (vls_handle_t vlsh) +{ + vcl_session_handle_t sh; + sh = vlsh_to_sh (vlsh); + return vppcom_session_index (sh); +} + +vls_handle_t +vls_session_index_to_vlsh (uint32_t session_index) +{ + vls_handle_t vlsh; + uword *vlshp; + + vls_table_rlock (); + vlshp = hash_get (vlsm->session_index_to_vlsh_table, session_index); + vlsh = vlshp ? *vlshp : VLS_INVALID_HANDLE; + vls_table_runlock (); + + return vlsh; +} + +int +vls_app_create (char *app_name) +{ + int rv; + if ((rv = vppcom_app_create (app_name))) + return rv; + clib_rwlock_init (&vlsm->vls_table_lock); + return VPPCOM_OK; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |