/* * * Copyright (c) 2018 Huawei Technologies Co.,Ltd. * 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 #include #include #include #include "nstack_dmm_api.h" #include "rsocket_adpt.h" #include "rdma/rsocket.h" #define RR_EVFD(u64) ((int)((u64) >> 32)) #define RR_RSFD(u64) ((int)((u64) & 0xFFFFFFFF)) #define RR_DATA(evfd, rsfd) ((((uint64_t)(evfd)) << 32) | (uint64_t)(uint32_t)(rsfd)) #define RR_EV_NUM 64 rsocket_var_t g_rr_var = { 0 }; rr_sapi_t g_sapi = { 0 }; int g_rr_log_level = -1; int rr_notify_event (void *pdata, int events) { int ret; ret = g_rr_var.event_cb (pdata, events); RR_DBG ("event_cb(%p, 0x%x)=%d,%d\n", pdata, events, ret, errno); return ret; } int rr_epoll_ctl (int op, int evfd, uint32_t events, int rsfd) { int ret; struct epoll_event event; event.events = events; event.data.u64 = RR_DATA (evfd, rsfd); ret = GSAPI (epoll_ctl) (g_rr_var.epfd, op, evfd, &event); return ret; } static void * rr_epoll_thread (void *arg) { int i, ret, e; struct epoll_event events[RR_EV_NUM]; while (1) { ret = GSAPI (epoll_wait) (g_rr_var.epfd, events, RR_EV_NUM, 100); e = errno; for (i = 0; i < ret; ++i) { if (rr_rs_handle (RR_RSFD (events[i].data.u64), events[i].events)) { (void) rr_ep_del (RR_EVFD (events[i].data.u64)); } } if (ret < 0) { RR_STAT_INC (RR_STAT_EPW_ERR); if (e == EINTR) { RR_STAT_INC (RR_STAT_EPW_EINTR); } else if (e == ETIMEDOUT) { RR_STAT_INC (RR_STAT_EPW_ETIMEOUT); } else { RR_ERR ("epoll_wait()=%d:%d\n", ret, errno); } } } return NULL; } static int rr_init_sapi () { void *handle = dlopen ("libc.so.6", RTLD_NOW | RTLD_GLOBAL); if (!handle) { RR_ERR ("dlopen(libc.so.6):NULL\n"); return -1; } #define RR_SAPI(name) \ GSAPI(name) = dlsym(handle, #name); \ if (!GSAPI(name)) \ RR_ERR("dlsym(" #name "):NULL\n"); #include "rsocket_sapi.h" #undef RR_SAPI return 0; } static void rr_init_log () { int level; char *log; if (g_rr_log_level >= 0) return; log = getenv ("RSOCKET_LOG"); if (!log || !log[0]) { g_rr_log_level = RR_LOG_OFF; return; } level = atoi (log); if (level < 0 || level > 99999) { g_rr_log_level = RR_LOG_OFF; return; } g_rr_log_level = level; } static int rsocket_init () { int ret; rr_init_log (); if (rr_init_sapi ()) { return -1; } g_rr_var.epfd = GSAPI (epoll_create) (1); if (g_rr_var.epfd < 0) return g_rr_var.epfd; ret = pthread_create (&g_rr_var.epoll_threadid, NULL, rr_epoll_thread, NULL); if (ret) { GSAPI (close) (g_rr_var.epfd); g_rr_var.epfd = -1; return ret; } (void) pthread_setname_np (g_rr_var.epoll_threadid, "rsocket_epoll"); return 0; } int rsocket_exit () { if (g_rr_var.epfd >= 0) { (void) GSAPI (close) (g_rr_var.epfd); g_rr_var.epfd = -1; } return 0; } unsigned int rsocket_ep_ctl (int epFD, int proFD, int ctl_ops, struct epoll_event *event, void *pdata) { int ret; struct eventpoll *ep; unsigned int revents = 0; RR_DBG ("(%d, %d, %d, 0x%x, %p)\n", epFD, proFD, ctl_ops, event->events, pdata); switch (ctl_ops) { case nstack_ep_triggle_add: ret = rr_rs_ep_add (proFD, pdata, &revents); if (ret) return -1; return revents; case nstack_ep_triggle_mod: ret = rr_rs_ep_mod (proFD, pdata, &revents); if (ret) return -1; return revents; case nstack_ep_triggle_del: return rr_rs_ep_del (proFD); } return _err (EPERM); } int rsocket_stack_register (nstack_proc_cb * proc_fun, nstack_event_cb * event_ops) { rr_init_log (); #define NSTACK_MK_DECL(ret, fn, args) \ do { \ proc_fun->socket_ops.pf##fn = dlsym(event_ops->handle, "r"#fn); \ if (!proc_fun->socket_ops.pf##fn) \ RR_LOG("socket API '" #fn "' not found\n"); \ } while (0) #include "declare_syscalls.h" #undef NSTACK_MK_DECL proc_fun->extern_ops.module_init = rsocket_init; proc_fun->extern_ops.ep_ctl = rsocket_ep_ctl; proc_fun->extern_ops.ep_getevt = NULL; proc_fun->extern_ops.module_init_child = rsocket_init; g_rr_var.type = event_ops->type; g_rr_var.event_cb = event_ops->event_cb; return 0; }