| /* |
| * 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: |
| */ |