void citp_log_fn_drv(const char* msg) { if( citp.log_fd < 0 ) { if( ef_onload_driver_open(&citp.log_fd, OO_STACK_DEV, 1) ) return; if( citp_fdtable.table ) citp_fdtable.table[citp.log_fd].fdip=fdi_to_fdip(&citp_the_reserved_fd); /* just to be sure: */ ci_sys_fcntl(citp.log_fd, F_SETFD, FD_CLOEXEC); } my_syscall3(ioctl, citp.log_fd, OO_IOC_PRINTK, (long) msg); }
static int ci_tcp_shutdown_listen(citp_socket* ep, int how, ci_fd_t fd) { ci_tcp_socket_listen* tls = SOCK_TO_TCP_LISTEN(ep->s); if( how == SHUT_WR ) return 0; ci_sock_lock(ep->netif, &tls->s.b); ci_netif_lock(ep->netif); LOG_TC(ci_log(SK_FMT" shutdown(SHUT_RD)", SK_PRI_ARGS(ep))); __ci_tcp_listen_shutdown(ep->netif, tls, fd); __ci_tcp_listen_to_normal(ep->netif, tls); { ci_fd_t os_sock = ci_get_os_sock_fd(ep, fd); int flags = ci_sys_fcntl(os_sock, F_GETFL); flags &= (~O_NONBLOCK); CI_TRY(ci_sys_fcntl(os_sock, F_SETFL, flags)); ci_rel_os_sock_fd(os_sock); } ci_netif_unlock(ep->netif); ci_sock_unlock(ep->netif, &tls->s.b); return 0; }
int ef_onload_handle_move_and_do_cloexec(ef_driver_handle* pfd, int do_cloexec) { int fd; if( do_cloexec ) fd = oo_fcntl_dupfd_cloexec(*pfd, CITP_OPTS.fd_base); else fd = ci_sys_fcntl(*pfd, F_DUPFD, CITP_OPTS.fd_base); /* If we've successfully done the dup then we've also set CLOEXEC if * needed on the new fd, so we're done. */ if( fd >= 0 ) { ci_tcp_helper_close_no_trampoline(*pfd); *pfd = fd; return 0; } else { LOG_NV(ci_log("%s: Failed to move fd from %d, rc %d", __func__, *pfd, fd)); } return fd; }
int citp_ep_dup_fcntl_dup_cloexec(int oldfd, long arg) { return ci_sys_fcntl(oldfd, F_DUPFD_CLOEXEC, arg); }
int citp_ep_dup_fcntl_dup(int oldfd, long arg) { return ci_sys_fcntl(oldfd, F_DUPFD, arg); }
int citp_epoll_create(int size, int flags) { citp_fdinfo *fdi; citp_epoll_fdi *epi; struct citp_epoll_fd* ep; int fd; if( (epi = CI_ALLOC_OBJ(citp_epoll_fdi)) == NULL ) goto fail0; if( (ep = CI_ALLOC_OBJ(struct citp_epoll_fd)) == NULL ) goto fail1; fdi = &epi->fdinfo; citp_fdinfo_init(fdi, &citp_epoll_protocol_impl); /* Create the epoll fd. */ CITP_FDTABLE_LOCK(); if( (fd = ci_sys_epoll_create_compat(size, flags, 0)) < 0 ) goto fail2; citp_fdtable_new_fd_set(fd, fdip_busy, TRUE); /* Init epfd_os */ #ifdef O_CLOEXEC ep->epfd_os = ci_sys_open(OO_EPOLL_DEV, O_RDWR | O_CLOEXEC); #else ep->epfd_os = ci_sys_open(OO_EPOLL_DEV, O_RDWR); if( ep->epfd_os >= 0 ) ci_sys_fcntl(ep->epfd_os, F_SETFD, FD_CLOEXEC); #endif if( ep->epfd_os < 0 ) { Log_E(ci_log("%s: ERROR: failed to open(%s) errno=%d", __FUNCTION__, OO_EPOLL_DEV, errno)); goto fail3; } __citp_fdtable_reserve(ep->epfd_os, 1); ep->shared = mmap(NULL, sizeof(*ep->shared), PROT_READ, MAP_SHARED, ep->epfd_os, 0); if( ep->shared == MAP_FAILED ) { Log_E(ci_log("%s: ERROR: failed to mmap shared segment errno=%d", __FUNCTION__, errno)); goto fail4; } __citp_fdtable_reserve(ep->shared->epfd, 1); CITP_FDTABLE_UNLOCK(); epi->epoll = ep; ep->size = size; oo_wqlock_init(&ep->lock); ep->not_mt_safe = ! CITP_OPTS.ul_epoll_mt_safe; ci_dllist_init(&ep->oo_sockets); ep->oo_sockets_n = 0; ci_dllist_init(&ep->dead_sockets); oo_atomic_set(&ep->refcount, 1); ep->epfd_syncs_needed = 0; ep->blocking = 0; citp_fdtable_insert(fdi, fd, 0); Log_POLL(ci_log("%s: fd=%d driver_fd=%d epfd=%d", __FUNCTION__, fd, ep->epfd_os, (int) ep->shared->epfd)); return fd; fail4: __citp_fdtable_reserve(ep->epfd_os, 0); ci_sys_close(ep->epfd_os); fail3: ci_sys_close(fd); citp_fdtable_busy_clear(fd, fdip_unknown, 1); fail2: CITP_FDTABLE_UNLOCK(); CI_FREE_OBJ(ep); fail1: CI_FREE_OBJ(epi); fail0: return -1; }
int ef_onload_driver_open(ef_driver_handle* pfd, enum oo_device_type dev_type, int do_cloexec) { int rc; int flags = 0; int saved_errno = errno; #ifdef O_CLOEXEC if( do_cloexec ) flags = O_CLOEXEC; #endif ci_assert(pfd); rc = oo_open(pfd, dev_type, flags); if( rc != 0 && errno != EMFILE && fd_is_saved[dev_type] >= 0 ) { ci_clone_fd_t op; op.do_cloexec = do_cloexec; LOG_NV(ci_log("%s: open failed, but cloning from saved fd", __func__)); rc = ci_sys_ioctl((ci_fd_t) saved_fd[dev_type], clone_ioctl[dev_type], &op); if( rc < 0 ) return rc; errno = saved_errno; *pfd = op.fd; } if( rc != 0 ) return rc; /* Our internal driver handles are not visible to the application. It may * make assumptions about the fd space available to it, and try to dup2/3 * onto one of our driver fds. To try and minimise this we allow the user * to specify a minimum value for us to use, to try and keep out of their * way. * * We have to be able to cope with them coming along and trying to dup onto * one of these fds anyway, as they may not have set the option up. As such * we treat failure to shift the fd as acceptable, and just retain the old * one. */ if( *pfd < CITP_OPTS.fd_base ) if( ef_onload_handle_move_and_do_cloexec(pfd, do_cloexec) == 0 ) return 0; if( do_cloexec ) { #if defined(O_CLOEXEC) static int o_cloexec_fails = -1; if( o_cloexec_fails < 0 ) { int arg; rc = ci_sys_fcntl(*(int *)pfd, F_GETFD, &arg); if( rc == 0 && (arg & FD_CLOEXEC) ) o_cloexec_fails = 0; else o_cloexec_fails = 1; } #else static const int o_cloexec_fails = 1; #endif if( o_cloexec_fails ) CI_DEBUG_TRY(ci_sys_fcntl(*(int *)pfd, F_SETFD, FD_CLOEXEC)); } return 0; }
/* fixme kostik: this is partially copy-paste from citp_sock_fcntl */ static int citp_pipe_fcntl(citp_fdinfo* fdinfo, int cmd, long arg) { int rc = 0; citp_pipe_fdi* epi = fdi_to_pipe_fdi(fdinfo); struct oo_pipe* p = epi->pipe; switch ( cmd ) { case F_GETFL: { ci_uint32 flag_nonb = CI_PFD_AFLAG_NONBLOCK; if( ! fdi_is_reader(fdinfo) ) { rc = O_WRONLY; flag_nonb <<= CI_PFD_AFLAG_WRITER_SHIFT; } else flag_nonb <<= CI_PFD_AFLAG_READER_SHIFT; if ( p->aflags & flag_nonb ) rc |= O_NONBLOCK; break; } case F_SETFL: { ci_uint32 bit; rc = ci_sys_fcntl(fdinfo->fd, cmd, arg); if( rc < 0 ) break; bit = CI_PFD_AFLAG_NONBLOCK << (fdi_is_reader(fdinfo) ? CI_PFD_AFLAG_READER_SHIFT : CI_PFD_AFLAG_WRITER_SHIFT); if( arg & (O_NONBLOCK | O_NDELAY) ) ci_bit_mask_set(&p->aflags, bit); else ci_bit_mask_clear(&p->aflags, bit); break; } case F_DUPFD: rc = citp_ep_dup(fdinfo->fd, citp_ep_dup_fcntl_dup, arg); break; #ifdef F_DUPFD_CLOEXEC case F_DUPFD_CLOEXEC: rc = citp_ep_dup(fdinfo->fd, citp_ep_dup_fcntl_dup_cloexec, arg); break; #endif case F_GETFD: case F_SETFD: rc = ci_sys_fcntl(fdinfo->fd, cmd, arg); break; case F_GETLK: case F_SETLK: case F_SETLKW: /* File locks not supported on sockets */ Log_U(ci_log("%s: cmd %d not supported on sockets!",__FUNCTION__, cmd)); errno = ENOTSUP; rc = CI_SOCKET_ERROR; break; case F_GETOWN: case F_SETOWN: #ifdef F_GETOWN_EX case F_GETOWN_EX: #endif #ifdef F_SETOWN_EX case F_SETOWN_EX: #endif rc = ci_sys_fcntl(fdinfo->fd, cmd, arg); if( rc != 0 ) break; p->b.sigown = arg; if( p->b.sigown && (p->b.sb_aflags & CI_SB_AFLAG_O_ASYNC) ) ci_bit_set(&p->b.wake_request, CI_SB_FLAG_WAKE_RX_B); break; #ifdef F_SETPIPE_SZ case F_SETPIPE_SZ: /* System pipe buf size is rounded up to power of two. We * cannot replicate this. */ rc = ci_pipe_set_size(epi->ni, p, arg); if( rc < 0 ) { errno = EINVAL; rc = CI_SOCKET_ERROR; break; } rc = 0; break; #endif #ifdef F_GETPIPE_SZ case F_GETPIPE_SZ: rc = (p->bufs_max - 1) * OO_PIPE_BUF_MAX_SIZE; break; #endif default: /* fixme kostik: logging should include some pipe identification */ errno = ENOTSUP; rc = CI_SOCKET_ERROR; } Log_VSC(log("%s(%d, %d, %ld) = %d (errno=%d)", __FUNCTION__, fdinfo->fd, cmd, arg, rc, errno)); return rc; }