mirror of https://github.com/F-Stack/f-stack.git
Merge branch 'preload_syscall' into dev
This commit is contained in:
commit
419e3b16fe
|
@ -0,0 +1,13 @@
|
|||
This directory stores some adapters based on the F-Stack lib library, currently includes `micro_thread` and `syscall`.
|
||||
|
||||
## micro_thread
|
||||
|
||||
Provides micro thread interface. Various applications with stateful applications can easily use F-Stack to get high performance without processing complex asynchronous logic.
|
||||
|
||||
## syscall
|
||||
|
||||
Hijack Linux kernel syscall with f-stack api, can use `LD_PRELOAD` to support existing applications, such as Nginx.
|
||||
|
||||
It also can support f-stack and kernel stack at the same time.
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
This is BSD 2-Clause licensed.
|
||||
Copyright (C) 2023 THL A29 Limited, a Tencent company.
|
||||
All rights reserved.
|
||||
|
||||
Terms of the BSD 2-Clause License:
|
||||
-----------------------------------------------------------------------------
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,107 @@
|
|||
TOPDIR=..
|
||||
|
||||
ifeq ($(FF_PATH),)
|
||||
FF_PATH=${TOPDIR}
|
||||
endif
|
||||
|
||||
ifneq ($(shell pkg-config --exists libdpdk && echo 0),0)
|
||||
$(error "No installation of DPDK found, maybe you should export environment variable `PKG_CONFIG_PATH`")
|
||||
endif
|
||||
|
||||
#DEBUG=-O0 -gdwarf-2 -g3
|
||||
|
||||
# Per thread separate initialization dpdk lib and attach sc when needed,
|
||||
# such as listen same port in different threads, and socket can use in own thread.
|
||||
# Default disable.
|
||||
#
|
||||
# If disable it, one socket can use in all threads.
|
||||
#FF_THREAD_SOCKET=1
|
||||
|
||||
# If enable FF_KERNEL_EVENT, epoll_create/epoll_clt/epoll_wait always call f-stack and system API at the same time.
|
||||
# Use for some scenarios similar to Nginx.
|
||||
#FF_KERNEL_EVENT=1
|
||||
|
||||
PKGCONF ?= pkg-config
|
||||
|
||||
ifndef DEBUG
|
||||
CFLAGS+= -g -O2 -DNDEBUG
|
||||
else
|
||||
CFLAGS+= ${DEBUG}
|
||||
endif
|
||||
|
||||
ifdef FF_THREAD_SOCKET
|
||||
CFLAGS+= -DFF_THREAD_SOCKET
|
||||
endif
|
||||
|
||||
ifdef FF_KERNEL_EVENT
|
||||
CFLAGS+= -DFF_KERNEL_EVENT
|
||||
endif
|
||||
|
||||
ifdef FF_MULTI_SC
|
||||
CFLAGS+= -DFF_MULTI_SC
|
||||
endif
|
||||
|
||||
CFLAGS += -fPIC -Wall -Werror $(shell $(PKGCONF) --cflags libdpdk)
|
||||
|
||||
INCLUDES= -I. -I${FF_PATH}/lib
|
||||
|
||||
LIBS+= -Wl,--no-whole-archive -lrt -lm -ldl -lcrypto -pthread -lnuma
|
||||
FF_LIBS= -L${FF_PATH}/lib -Wl,--whole-archive,-lfstack,--no-whole-archive
|
||||
|
||||
DPDK_LIBS+= $(shell $(PKGCONF) --static --libs libdpdk)
|
||||
DPDK_LIBS+= ${LIBS}
|
||||
|
||||
#DPDK_CFLAGS= -Wall -Werror -include ${FF_DPDK}/include/rte_config.h
|
||||
#DPDK_CFLAGS+= -march=native -DRTE_MACHINE_CPUFLAG_SSE -DRTE_MACHINE_CPUFLAG_SSE2 -DRTE_MACHINE_CPUFLAG_SSE3
|
||||
#DPDK_CFLAGS+= -DRTE_MACHINE_CPUFLAG_SSSE3 -DRTE_MACHINE_CPUFLAG_SSE4_1 -DRTE_MACHINE_CPUFLAG_SSE4_2
|
||||
#DPDK_CFLAGS+= -DRTE_COMPILE_TIME_CPUFLAGS=RTE_CPUFLAG_SSE,RTE_CPUFLAG_SSE2,RTE_CPUFLAG_SSE3,RTE_CPUFLAG_SSSE3,RTE_CPUFLAG_SSE4_1,RTE_CPUFLAG_SSE4_2
|
||||
#DPDK_CFLAGS+= -I${FF_DPDK}/include
|
||||
|
||||
CFLAGS+= ${INCLUDES} ${DPDK_CFLAGS}
|
||||
|
||||
FSTACK_LIBS= ${FF_LIBS} ${DPDK_LIBS}
|
||||
FF_SYSCALL_LIBS=
|
||||
|
||||
FSTACK_SRCS= \
|
||||
fstack.c \
|
||||
ff_so_zone.c \
|
||||
ff_socket_ops.c
|
||||
|
||||
FF_SYSCALL_SRCS= \
|
||||
ff_so_zone.c \
|
||||
ff_hook_syscall.c \
|
||||
ff_linux_syscall.c
|
||||
|
||||
FSTACK_OBJS= $(patsubst %.c,%.o,${FSTACK_SRCS})
|
||||
|
||||
FF_SYSCALL_OBJS= $(patsubst %.c,%.o,${FF_SYSCALL_SRCS})
|
||||
|
||||
#TARGET= fstack libff_syscall.a
|
||||
TARGET= fstack libff_syscall.so example
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
fstack: ${FSTACK_OBJS}
|
||||
cc -o $@ $^ ${FSTACK_LIBS}
|
||||
|
||||
#libff_syscall.a: ${FF_SYSCALL_OBJS}
|
||||
libff_syscall.so: ${FF_SYSCALL_OBJS}
|
||||
#ar -rcs $@ $^ ${FF_SYSCALL_LIBS}
|
||||
${CC} -fPIC -shared -o $@ $^ ${FF_SYSCALL_LIBS} ${DPDK_LIBS}
|
||||
|
||||
example:
|
||||
cc ${CFLAGS} -I ${FF_PATH}/adapter/syscall -L ${FF_PATH}/adapter/syscall -lff_syscall -o helloworld_stack main_stack.c ${LIBS}
|
||||
cc ${CFLAGS} -I ${FF_PATH}/adapter/syscall -L ${FF_PATH}/adapter/syscall -lff_syscall -o helloworld_stack_thread_socket main_stack_thread_socket.c ${LIBS}
|
||||
cc ${CFLAGS} -I ${FF_PATH}/adapter/syscall -o helloworld_stack_epoll main_stack_epoll.c ${LIBS}
|
||||
cc ${CFLAGS} -I ${FF_PATH}/adapter/syscall -o helloworld_stack_epoll_thread_socket main_stack_epoll_thread_socket.c ${LIBS}
|
||||
cc ${CFLAGS} -I ${FF_PATH}/adapter/syscall -o helloworld_stack_epoll_kernel main_stack_epoll_kernel.c ${LIBS}
|
||||
|
||||
${FSTACK_OBJS}: %.o: %.c
|
||||
${CC} -c $(CFLAGS) ${PROF} $<
|
||||
|
||||
${FF_SYSCALL_OBJS}: %.o: %.c
|
||||
${CC} -c $(CFLAGS) ${PROF} $<
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o ${TARGET}
|
|
@ -0,0 +1,4 @@
|
|||
# F-Stack LD_PRELOAD Beta Introduction
|
||||
|
||||
[To be translated](https://mp.weixin.qq.com/s?__biz=MzI5ODY3Nzc5OA==&tempkey=MTIxNl9Kd0pabEJ4em95c3J6OFJJdUYzZ2F2aGthLURKQmplYnJIVmE0cTFsSzNqdkhFM3JjV1F1SjlrMWFxeVo0Nks0b0lwOG5UbEZueVRTb0RFcnQ5LW42UE1aNVFUYW9mMHVaRjFiWXBKcG9VY0FYTTJIdUgxcU5UdTltb0hId0EtODBHR3lZM1FuX1FxdHNMQkJsWExTb3IyQ0MycDkxWXlBTllNOVlBfn4%3D&chksm=eca3623edbd4eb28e8d7dc68001f46381d39f4ffca91037a4ad8f8ed5b59bad2354ca273601b&token=39899456&lang=zh_CN#rd).
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef _FF_ADAPTER_H
|
||||
#define _FF_ADAPTER_H
|
||||
|
||||
/* socket.h */
|
||||
//#define SOCK_CLOEXEC 0x10000000
|
||||
//#define SOCK_NONBLOCK 0x20000000
|
||||
#define SOCK_FSTACK 0x01000000
|
||||
#define SOCK_KERNEL 0x02000000
|
||||
|
||||
int ff_adapter_init();
|
||||
//int __attribute__((constructor)) ff_adapter_init(int argc, char * const argv[]);
|
||||
|
||||
void alarm_event_sem();
|
||||
|
||||
/*-
|
||||
* Verify whether the socket is supported by fstack or not.
|
||||
*/
|
||||
int fstack_territory(int domain, int type, int protocol);
|
||||
|
||||
/* Tell whether a 'sockfd' belongs to fstack. */
|
||||
int is_fstack_fd(int fd);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
FF_SYSCALL_DECL(int, socket, (int, int, int));
|
||||
FF_SYSCALL_DECL(int, bind, (int, const struct sockaddr *, socklen_t));
|
||||
FF_SYSCALL_DECL(int, listen, (int, int));
|
||||
FF_SYSCALL_DECL(int, shutdown, (int, int));
|
||||
FF_SYSCALL_DECL(int, getsockname, (int, struct sockaddr *, socklen_t *));
|
||||
FF_SYSCALL_DECL(int, getpeername, (int, struct sockaddr *, socklen_t *));
|
||||
FF_SYSCALL_DECL(int, getsockopt, (int, int, int, void *, socklen_t *));
|
||||
FF_SYSCALL_DECL(int, setsockopt, (int, int, int, const void *, socklen_t));
|
||||
FF_SYSCALL_DECL(int, accept, (int, struct sockaddr *, socklen_t *));
|
||||
FF_SYSCALL_DECL(int, accept4,(int, struct sockaddr *, socklen_t *, int flags));
|
||||
FF_SYSCALL_DECL(int, connect, (int, const struct sockaddr *, socklen_t));
|
||||
FF_SYSCALL_DECL(ssize_t, recv, (int, void *, size_t, int));
|
||||
FF_SYSCALL_DECL(ssize_t, send, (int, const void *, size_t, int));
|
||||
FF_SYSCALL_DECL(ssize_t, read, (int, void *, size_t));
|
||||
FF_SYSCALL_DECL(ssize_t, write, (int, const void *, size_t));
|
||||
FF_SYSCALL_DECL(ssize_t, writev, (int, const struct iovec *, int));
|
||||
FF_SYSCALL_DECL(ssize_t, readv, (int, const struct iovec *, int));
|
||||
FF_SYSCALL_DECL(ssize_t, sendto, (int, const void *, size_t, int,
|
||||
const struct sockaddr *, socklen_t));
|
||||
FF_SYSCALL_DECL(ssize_t, recvfrom, (int, void *, size_t, int,
|
||||
struct sockaddr *, socklen_t *));
|
||||
FF_SYSCALL_DECL(ssize_t, sendmsg, (int, const struct msghdr *, int flags));
|
||||
FF_SYSCALL_DECL(ssize_t, recvmsg, (int, struct msghdr *, int flags));
|
||||
FF_SYSCALL_DECL(int, close, (int));
|
||||
FF_SYSCALL_DECL(int, ioctl, (int, unsigned long, unsigned long));
|
||||
FF_SYSCALL_DECL(int, fcntl, (int, int, unsigned long));
|
||||
FF_SYSCALL_DECL(int, epoll_create, (int));
|
||||
FF_SYSCALL_DECL(int, epoll_ctl, (int, int, int, struct epoll_event *));
|
||||
FF_SYSCALL_DECL(int, epoll_wait, (int, struct epoll_event *, int, int));
|
||||
FF_SYSCALL_DECL(pid_t, fork, (void));
|
||||
#undef FF_SYSCALL_DECL
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,12 @@
|
|||
#ifndef _FF_HOOK_SYSCALL_H
|
||||
#define _FF_HOOK_SYSCALL_H
|
||||
|
||||
#undef FF_SYSCALL_DECL
|
||||
#define FF_SYSCALL_DECL(ret, fn, args) extern ret ff_hook_##fn args
|
||||
#include <ff_declare_syscalls.h>
|
||||
|
||||
extern int kqueue(void);
|
||||
extern int kevent(int kq, const struct kevent *changelist, int nchanges,
|
||||
struct kevent *eventlist, int nevents, const struct timespec *timeout);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,256 @@
|
|||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "ff_socket_ops.h"
|
||||
#include "ff_linux_syscall.h"
|
||||
|
||||
#define SYSCALL(symbol, para) { \
|
||||
if (linux_syscall_inited == 0) { \
|
||||
if (linux_syscall_init() != 0) { \
|
||||
return -1; \
|
||||
} \
|
||||
} \
|
||||
if (syscalls.pf_##symbol) { \
|
||||
return syscalls.pf_##symbol para; \
|
||||
} \
|
||||
errno = ENOSYS; \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
struct ff_linux_syscall {
|
||||
#define FF_SYSCALL_DECL(ret, fn, args) ret (*pf_##fn) args;
|
||||
#include "ff_declare_syscalls.h"
|
||||
};
|
||||
|
||||
static int linux_syscall_inited;
|
||||
|
||||
static struct ff_linux_syscall syscalls = { 0 };
|
||||
|
||||
static void *linux_lib_handle = NULL;
|
||||
|
||||
pthread_mutex_t syscall_init_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static inline int
|
||||
linux_syscall_load_symbol()
|
||||
{
|
||||
linux_lib_handle = dlopen ("libc.so.6", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (linux_lib_handle == NULL) {
|
||||
ERR_LOG("cannot dlopen libc.so.6] err_string=%s", dlerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define FF_SYSCALL_DECL(ret, fn, args) \
|
||||
syscalls.pf_##fn = (typeof(syscalls.pf_##fn))dlsym(linux_lib_handle, #fn);
|
||||
#include <ff_declare_syscalls.h>
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
linux_syscall_init()
|
||||
{
|
||||
if (linux_syscall_inited) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&syscall_init_mutex);
|
||||
if (linux_syscall_inited) {
|
||||
pthread_mutex_unlock(&syscall_init_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (linux_syscall_load_symbol() != 0) {
|
||||
pthread_mutex_unlock(&syscall_init_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
linux_syscall_inited = 1;
|
||||
|
||||
pthread_mutex_unlock(&syscall_init_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ff_linux_socket(int domain, int type, int protocol)
|
||||
{
|
||||
ERR_LOG("ff_linux_socket, domain:%d, type:%d, protocol:%d\n", domain, type, protocol);
|
||||
SYSCALL(socket, (domain, type, protocol));
|
||||
}
|
||||
|
||||
int
|
||||
ff_linux_bind(int s, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
ERR_LOG("ff_linux_bind, fd:%d, addr:%p, addrlen:%u\n", s, addr, addrlen);
|
||||
SYSCALL(bind, (s, addr, addrlen));
|
||||
}
|
||||
|
||||
int
|
||||
ff_linux_listen(int s, int backlog)
|
||||
{
|
||||
ERR_LOG("ff_linux_listen, fd:%d, backlog:%d\n", s, backlog);
|
||||
SYSCALL(listen, (s, backlog));
|
||||
}
|
||||
|
||||
int ff_linux_shutdown(int s, int how)
|
||||
{
|
||||
SYSCALL(shutdown, (s, how));
|
||||
}
|
||||
|
||||
int ff_linux_getsockname(int s, struct sockaddr *name,
|
||||
socklen_t *namelen)
|
||||
{
|
||||
SYSCALL(getsockname, (s, name, namelen));
|
||||
}
|
||||
|
||||
int ff_linux_getpeername(int s, struct sockaddr *name,
|
||||
socklen_t *namelen)
|
||||
{
|
||||
SYSCALL(getpeername, (s, name, namelen));
|
||||
}
|
||||
|
||||
int ff_linux_getsockopt(int s, int level, int optname,
|
||||
void *optval, socklen_t *optlen)
|
||||
{
|
||||
SYSCALL(getsockopt, (s, level, optname, optval, optlen));
|
||||
}
|
||||
|
||||
int ff_linux_setsockopt(int s, int level, int optname,
|
||||
const void *optval, socklen_t optlen)
|
||||
{
|
||||
SYSCALL(setsockopt, (s, level, optname, optval, optlen));
|
||||
}
|
||||
|
||||
int ff_linux_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_accept, fd:%d, addr:%p, len:%p\n", s, addr, addrlen);
|
||||
SYSCALL(accept, (s, addr, addrlen));
|
||||
}
|
||||
|
||||
int ff_linux_accept4(int s, struct sockaddr *addr,
|
||||
socklen_t *addrlen, int flags)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_accept4, fd:%d, addr:%p, addrlen:%p, flags:%d\n", s, addr, addrlen, flags);
|
||||
SYSCALL(accept4, (s, addr, addrlen, flags));
|
||||
}
|
||||
|
||||
int ff_linux_connect(int s, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_connect, fd:%d, addr:%p, addrlen:%u\n", s, addr, addrlen);
|
||||
SYSCALL(connect, (s, addr, addrlen));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_recv(int s, void *buf, size_t len, int flags)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_recv, fd:%d, buf:%p, len:%lu, flags:%d\n", s, buf, len, flags);
|
||||
SYSCALL(recv, (s, buf, len, flags));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_send(int s, const void *buf, size_t len, int flags)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_send, fd:%d, buf:%p, len:%lu, flags:%d\n", s, buf, len, flags);
|
||||
SYSCALL(send, (s, buf, len, flags));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_read(int s, void *buf, size_t len)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_read, fd:%d, buf:%p, len:%lu\n", s, buf, len);
|
||||
SYSCALL(read, (s, buf, len));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_write(int s, const void *buf, size_t len)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_write, fd:%d, buf:%p, len:%lu\n", s, buf, len);
|
||||
SYSCALL(write, (s, buf, len));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_writev(int s, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_writev, fd:%d, iov:%p, iovcnt:%d\n", s, iov, iovcnt);
|
||||
SYSCALL(writev, (s, iov, iovcnt));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_readv(int s, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_readv, fd:%d, iov:%p, iovcnt:%d\n", s, iov, iovcnt);
|
||||
SYSCALL(readv, (s, iov, iovcnt));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_sendto(int s, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_sendto, fd:%d, buf:%p, len:%lu, flags:%d, to:%p, tolen:%d\n",
|
||||
s, buf, len, flags, to, tolen);
|
||||
SYSCALL(sendto, (s, buf, len, flags, to, tolen));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_recvfrom(int s, void *buf, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
|
||||
{
|
||||
DEBUG_LOG("ff_linux_recvfrom, fd:%d, buf:%p, len:%lu, flags:%d, from:%p, fromlen:%p\n",
|
||||
s, buf, len, flags, from, fromlen);
|
||||
SYSCALL(recvfrom, (s, buf, len, flags, from, fromlen));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_sendmsg(int s, const struct msghdr *msg, int flags)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_sendmsg, fd:%d, msg:%p, flags:%d\n",
|
||||
s, msg, flags);
|
||||
SYSCALL(sendmsg, (s, msg, flags));
|
||||
}
|
||||
|
||||
ssize_t ff_linux_recvmsg(int s, struct msghdr *msg, int flags)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_recvmsg, fd:%d, msg:%p, flags:%d\n", s, msg, flags);
|
||||
SYSCALL(recvmsg, (s, msg, flags))
|
||||
}
|
||||
|
||||
int ff_linux_close(int s)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_close, fd:%d\n", s);
|
||||
SYSCALL(close, (s));
|
||||
}
|
||||
|
||||
int ff_linux_ioctl(int s, unsigned long req, unsigned long data)
|
||||
{
|
||||
SYSCALL(ioctl, (s, req, data));
|
||||
}
|
||||
|
||||
int ff_linux_fcntl(int s, int cmd, unsigned long data)
|
||||
{
|
||||
SYSCALL(fcntl, (s, cmd, data));
|
||||
}
|
||||
|
||||
int ff_linux_epoll_create(int size)
|
||||
{
|
||||
ERR_LOG("ff_linux_epoll_create, fdsize:%d\n", size);
|
||||
SYSCALL(epoll_create, (size));
|
||||
}
|
||||
|
||||
int ff_linux_epoll_ctl(int epfd, int op, int fd,
|
||||
struct epoll_event *event)
|
||||
{
|
||||
ERR_LOG("ff_linux_epoll_ctl, epfd:%d, op:%d, fd:%d\n", epfd, op, fd);
|
||||
SYSCALL(epoll_ctl, (epfd, op, fd, event));
|
||||
}
|
||||
|
||||
int
|
||||
ff_linux_epoll_wait(int epfd, struct epoll_event *events,
|
||||
int maxevents, int timeout)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_epoll_wait, epfd:%d, maxevents:%d, timeout:%d\n", epfd, maxevents, timeout);
|
||||
SYSCALL(epoll_wait, (epfd, events, maxevents, timeout));
|
||||
}
|
||||
|
||||
pid_t
|
||||
ff_linux_fork(void)
|
||||
{
|
||||
DEBUG_LOG("ff_linux_fork\n");
|
||||
SYSCALL(fork, ());
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef _FF_LINUX_SYSCALL_H_
|
||||
#define _FF_LINUX_SYSCALL_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#undef FF_SYSCALL_DECL
|
||||
#define FF_SYSCALL_DECL(ret, fn, args) ret ff_linux_##fn args
|
||||
#include "ff_declare_syscalls.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,234 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rte_eal.h>
|
||||
#include <rte_memzone.h>
|
||||
|
||||
#include "ff_config.h"
|
||||
#include "ff_socket_ops.h"
|
||||
|
||||
#define SOCKET_OPS_ZONE_NAME "ff_socket_ops_zone_%d"
|
||||
|
||||
#define SOCKET_OPS_CONTEXT_NAME_SIZE 32
|
||||
#define SOCKET_OPS_CONTEXT_NAME "ff_so_context_"
|
||||
|
||||
static uint16_t ff_max_so_context = SOCKET_OPS_CONTEXT_MAX_NUM;
|
||||
__FF_THREAD struct ff_socket_ops_zone *ff_so_zone;
|
||||
#ifdef FF_MULTI_SC
|
||||
struct ff_socket_ops_zone *ff_so_zones[SOCKET_OPS_CONTEXT_MAX_NUM] = {NULL};
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
is_power_of_2(uint64_t n)
|
||||
{
|
||||
return (n != 0 && ((n & (n - 1)) == 0));
|
||||
}
|
||||
|
||||
int
|
||||
ff_set_max_so_context(uint16_t count)
|
||||
{
|
||||
if (ff_so_zone) {
|
||||
ERR_LOG("Can not set: memzone has inited\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
|
||||
ERR_LOG("Can not set: process is not primary\n");
|
||||
return 1;
|
||||
}*/
|
||||
|
||||
if (!is_power_of_2(count)) {
|
||||
ERR_LOG("Can not set: count:%d is not power of 2, use default:%d\n",
|
||||
count, ff_max_so_context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (count > SOCKET_OPS_CONTEXT_MAX_NUM) {
|
||||
count = SOCKET_OPS_CONTEXT_MAX_NUM;
|
||||
}
|
||||
|
||||
ff_max_so_context = count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ff_create_so_memzone()
|
||||
{
|
||||
if (ff_so_zone) {
|
||||
ERR_LOG("Can not create memzone: memzone has inited\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
|
||||
uint16_t i, proc_id;
|
||||
for (proc_id = 0; proc_id < ff_global_cfg.dpdk.nb_procs; proc_id++) {
|
||||
struct ff_socket_ops_zone *so_zone_tmp;
|
||||
const struct rte_memzone *mz;
|
||||
char zn[64];
|
||||
|
||||
size_t zone_size = sizeof(struct ff_socket_ops_zone) +
|
||||
sizeof(struct ff_so_context) * ff_max_so_context;
|
||||
snprintf(zn, sizeof(zn), SOCKET_OPS_ZONE_NAME, proc_id);
|
||||
ERR_LOG("To create memzone:%s\n", zn);
|
||||
|
||||
mz = rte_memzone_reserve(zn, zone_size, rte_socket_id(), 0);
|
||||
if (mz == NULL) {
|
||||
ERR_LOG("Cannot reserve memory zone:%s\n", zn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(mz->addr, 0, zone_size);
|
||||
so_zone_tmp = mz->addr;
|
||||
|
||||
rte_spinlock_init(&so_zone_tmp->lock);
|
||||
so_zone_tmp->count = ff_max_so_context;
|
||||
so_zone_tmp->mask = so_zone_tmp->count - 1;
|
||||
so_zone_tmp->free = so_zone_tmp->count;
|
||||
so_zone_tmp->idx = 0;
|
||||
memset(so_zone_tmp->inuse, 0, SOCKET_OPS_CONTEXT_MAX_NUM);
|
||||
so_zone_tmp->sc = (struct ff_so_context *)(so_zone_tmp + 1);
|
||||
|
||||
for (i = 0; i < ff_max_so_context; i++) {
|
||||
struct ff_so_context *sc = &so_zone_tmp->sc[i];
|
||||
rte_spinlock_init(&sc->lock);
|
||||
sc->status = FF_SC_IDLE;
|
||||
sc->idx = i;
|
||||
sc->refcount = 0;
|
||||
//so_zone_tmp->inuse[i] = 0;
|
||||
|
||||
if (sem_init(&sc->wait_sem, 1, 0) == -1) {
|
||||
ERR_LOG("Initialize semaphore failed:%d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_id == 0) {
|
||||
ff_so_zone = so_zone_tmp;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
const struct rte_memzone *mz;
|
||||
char zn[64];
|
||||
|
||||
snprintf(zn, sizeof(zn), SOCKET_OPS_ZONE_NAME, ff_global_cfg.dpdk.proc_id);
|
||||
ERR_LOG("To lookup memzone:%s\n", zn);
|
||||
|
||||
mz = rte_memzone_lookup(zn);
|
||||
if (mz == NULL) {
|
||||
ERR_LOG("Lookup memory zone:%s failed\n", zn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ff_so_zone = mz->addr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ff_so_context *
|
||||
ff_attach_so_context(int idx)
|
||||
{
|
||||
struct ff_so_context *sc = NULL;
|
||||
uint16_t i;
|
||||
|
||||
#ifdef FF_MULTI_SC
|
||||
ff_so_zone = ff_so_zones[idx];
|
||||
#endif
|
||||
|
||||
DEBUG_LOG("proc_id:%d, ff_so_zone:%p\n", idx, ff_so_zone);
|
||||
|
||||
if (ff_so_zone == NULL) {
|
||||
const struct rte_memzone *mz;
|
||||
char zn[64];
|
||||
|
||||
snprintf(zn, sizeof(zn), SOCKET_OPS_ZONE_NAME, idx);
|
||||
ERR_LOG("To lookup memzone:%s\n", zn);
|
||||
|
||||
mz = rte_memzone_lookup(zn);
|
||||
if (mz == NULL) {
|
||||
ERR_LOG("Lookup memory zone:%s failed\n", zn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ff_so_zone = mz->addr;
|
||||
|
||||
#ifdef FF_MULTI_SC
|
||||
ff_so_zones[idx] = ff_so_zone;
|
||||
ERR_LOG("FF_MULTI_SC f_so_zones[%d]:%p\n", idx, ff_so_zones[idx]);
|
||||
#endif
|
||||
}
|
||||
|
||||
rte_spinlock_lock(&ff_so_zone->lock);
|
||||
|
||||
if (ff_so_zone->free == 0) {
|
||||
ERR_LOG("Attach memzone failed: no free context\n");
|
||||
rte_spinlock_unlock(&ff_so_zone->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ff_so_zone->count; i++) {
|
||||
uint16_t idx = (ff_so_zone->idx + i) & ff_so_zone->mask;
|
||||
sc = &ff_so_zone->sc[idx];
|
||||
if (ff_so_zone->inuse[idx] == 0) {
|
||||
ff_so_zone->inuse[idx] = 1;
|
||||
rte_spinlock_init(&sc->lock);
|
||||
sc->status = FF_SC_IDLE;
|
||||
sc->refcount = 1;
|
||||
ff_so_zone->free--;
|
||||
ff_so_zone->idx = idx + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(i == ff_so_zone->count)) {
|
||||
ERR_LOG("Attach memzone failed: instance %d no free context,"
|
||||
" fetel error of so status, all sc inuse, count:%d, free:%d\n",
|
||||
idx, ff_so_zone->count, ff_so_zone->free);
|
||||
sc = NULL;
|
||||
}
|
||||
|
||||
ERR_LOG("attach sc:%p, so count:%d, free:%d, idx:%d, i:%d\n",
|
||||
sc, ff_so_zone->count, ff_so_zone->free, ff_so_zone->idx, i);
|
||||
|
||||
rte_spinlock_unlock(&ff_so_zone->lock);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
void
|
||||
ff_detach_so_context(struct ff_so_context *sc)
|
||||
{
|
||||
ERR_LOG("ff_so_zone:%p, sc:%p\n", ff_so_zone, sc);
|
||||
|
||||
if (ff_so_zone == NULL || sc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_LOG("detach sc:%p, ops:%d, status:%d, idx:%d, sc->refcount:%d, inuse:%d, so free:%u, idx:%u\n",
|
||||
sc, sc->ops, sc->status, sc->idx, sc->refcount, ff_so_zone->inuse[sc->idx], ff_so_zone->free, ff_so_zone->idx);
|
||||
|
||||
rte_spinlock_lock(&ff_so_zone->lock);
|
||||
rte_spinlock_lock(&sc->lock);
|
||||
|
||||
if (sc->refcount > 1) {
|
||||
ERR_LOG("sc refcount > 1, to sub it, sc:%p, ops:%d, status:%d, idx:%d, sc->refcount:%d, inuse:%d, so free:%u, idx:%u\n",
|
||||
sc, sc->ops, sc->status, sc->idx, sc->refcount, ff_so_zone->inuse[sc->idx], ff_so_zone->free, ff_so_zone->idx);
|
||||
sc->refcount--;
|
||||
} else {
|
||||
ERR_LOG("sc refcount is 1, to detach it, sc:%p, ops:%d, status:%d, idx:%d, sc->refcount:%d, inuse:%d, so free:%u, idx:%u\n",
|
||||
sc, sc->ops, sc->status, sc->idx, sc->refcount, ff_so_zone->inuse[sc->idx], ff_so_zone->free, ff_so_zone->idx);
|
||||
if (ff_so_zone->inuse[sc->idx] == 1) {
|
||||
ff_so_zone->inuse[sc->idx] = 0;
|
||||
|
||||
ff_so_zone->free++;
|
||||
ff_so_zone->idx = sc->idx;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_LOG("detach sc:%p, ops:%d, status:%d, idx:%d, sc->refcount:%d, inuse:%d, so free:%u, idx:%u\n",
|
||||
sc, sc->ops, sc->status, sc->idx, sc->refcount, ff_so_zone->inuse[sc->idx], ff_so_zone->free, ff_so_zone->idx);
|
||||
|
||||
rte_spinlock_unlock(&sc->lock);
|
||||
rte_spinlock_unlock(&ff_so_zone->lock);
|
||||
}
|
|
@ -0,0 +1,553 @@
|
|||
#include <rte_memcpy.h>
|
||||
#include <rte_spinlock.h>
|
||||
|
||||
#include "ff_socket_ops.h"
|
||||
#include "ff_sysproto.h"
|
||||
#include "ff_api.h"
|
||||
#include "ff_epoll.h"
|
||||
#include "ff_config.h"
|
||||
|
||||
#undef FF_SYSCALL_DECL
|
||||
#define FF_SYSCALL_DECL(ret, fn, none) \
|
||||
static ret ff_sys_##fn(struct ff_##fn##_args *args);
|
||||
#include <ff_declare_syscalls.h>
|
||||
static int ff_sys_kqueue(struct ff_kqueue_args *args);
|
||||
static int ff_sys_kevent(struct ff_kevent_args *args);
|
||||
|
||||
#define FF_MAX_BOUND_NUM 8
|
||||
|
||||
/* Where to call sem_post in kevent or epoll_wait */
|
||||
static int sem_flag = 0;
|
||||
|
||||
/*
|
||||
* The event num kevent or epoll_wait returned.
|
||||
* Use for burst process event in one F-Stack loop to improve performance.
|
||||
*/
|
||||
#define EVENT_LOOP_TIMES 32
|
||||
static int ff_event_loop_nb = 0;
|
||||
//static int ff_next_event_flag = 0;
|
||||
|
||||
struct ff_bound_info {
|
||||
int fd;
|
||||
struct sockaddr addr;
|
||||
};
|
||||
|
||||
static struct ff_bound_info ff_bound_fds[FF_MAX_BOUND_NUM];
|
||||
|
||||
static int
|
||||
sockaddr_cmp(struct sockaddr *a, struct sockaddr *b)
|
||||
{
|
||||
struct sockaddr_in *sina, *sinb;
|
||||
sina = (struct sockaddr_in *)a;
|
||||
sinb = (struct sockaddr_in *)b;
|
||||
|
||||
if (sina->sin_family != sinb->sin_family) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sina->sin_port != sinb->sin_port) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sina->sin_addr.s_addr != sinb->sin_addr.s_addr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sockaddr_is_bound(struct sockaddr *addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FF_MAX_BOUND_NUM; i++) {
|
||||
struct ff_bound_info *info = &ff_bound_fds[i];
|
||||
if (info->fd == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sockaddr_cmp(&info->addr, addr) == 0) {
|
||||
return info->fd;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sockaddr_bind(int fd, struct sockaddr *addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FF_MAX_BOUND_NUM; i++) {
|
||||
struct ff_bound_info *info = &ff_bound_fds[i];
|
||||
if (info->fd != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info->fd = fd;
|
||||
rte_memcpy(&info->addr, addr, sizeof(struct sockaddr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
sockaddr_unbind(int fd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FF_MAX_BOUND_NUM; i++) {
|
||||
struct ff_bound_info *info = &ff_bound_fds[i];
|
||||
if (info->fd != fd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info->fd = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_socket(struct ff_socket_args *args)
|
||||
{
|
||||
return ff_socket(args->domain, args->type, args->protocol);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_bind(struct ff_bind_args *args)
|
||||
{
|
||||
int bound_fd;
|
||||
int ret;
|
||||
|
||||
bound_fd = sockaddr_is_bound(args->addr);
|
||||
if (bound_fd != 0 && bound_fd != args->fd) {
|
||||
return ff_dup2(bound_fd, args->fd);
|
||||
}
|
||||
|
||||
ret = ff_bind(args->fd, args->addr, args->addrlen);
|
||||
if (ret == 0) {
|
||||
sockaddr_bind(args->fd, args->addr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_listen(struct ff_listen_args *args)
|
||||
{
|
||||
return ff_listen(args->fd, args->backlog);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_shutdown(struct ff_shutdown_args *args)
|
||||
{
|
||||
return ff_shutdown(args->fd, args->how);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_getsockname(struct ff_getsockname_args *args)
|
||||
{
|
||||
return ff_getsockname(args->fd, args->name, args->namelen);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_getpeername(struct ff_getpeername_args *args)
|
||||
{
|
||||
return ff_getpeername(args->fd, args->name, args->namelen);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_getsockopt(struct ff_getsockopt_args *args)
|
||||
{
|
||||
return ff_getsockopt(args->fd, args->level, args->name,
|
||||
args->optval, args->optlen);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_setsockopt(struct ff_setsockopt_args *args)
|
||||
{
|
||||
return ff_setsockopt(args->fd, args->level, args->name,
|
||||
args->optval, args->optlen);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_accept(struct ff_accept_args *args)
|
||||
{
|
||||
return ff_accept(args->fd, args->addr, args->addrlen);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_accept4(struct ff_accept4_args *args)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_connect(struct ff_connect_args *args)
|
||||
{
|
||||
return ff_connect(args->fd, args->addr, args->addrlen);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_recv(struct ff_recv_args *args)
|
||||
{
|
||||
return ff_recv(args->fd, args->buf, args->len, args->flags);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_recvfrom(struct ff_recvfrom_args *args)
|
||||
{
|
||||
return ff_recvfrom(args->fd, args->buf, args->len, args->flags,
|
||||
args->from, args->fromlen);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_recvmsg(struct ff_recvmsg_args *args)
|
||||
{
|
||||
return ff_recvmsg(args->fd, args->msg, args->flags);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_read(struct ff_read_args *args)
|
||||
{
|
||||
DEBUG_LOG("ff_sys_read, fd:%d, len:%lu\n", args->fd, args->len);
|
||||
return ff_read(args->fd, args->buf, args->len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_readv(struct ff_readv_args *args)
|
||||
{
|
||||
return ff_readv(args->fd, args->iov, args->iovcnt);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_send(struct ff_send_args *args)
|
||||
{
|
||||
return ff_send(args->fd, args->buf, args->len, args->flags);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_sendto(struct ff_sendto_args *args)
|
||||
{
|
||||
return ff_sendto(args->fd, args->buf, args->len, args->flags,
|
||||
args->to, args->tolen);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_sendmsg(struct ff_sendmsg_args *args)
|
||||
{
|
||||
return ff_sendmsg(args->fd, args->msg, args->flags);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_write(struct ff_write_args *args)
|
||||
{
|
||||
DEBUG_LOG("ff_sys_write, fd:%d, len:%lu\n", args->fd, args->len);
|
||||
return ff_write(args->fd, args->buf, args->len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ff_sys_writev(struct ff_writev_args *args)
|
||||
{
|
||||
return ff_writev(args->fd, args->iov, args->iovcnt);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_close(struct ff_close_args *args)
|
||||
{
|
||||
DEBUG_LOG("ff_sys_close, fd:%d\n", args->fd);
|
||||
sockaddr_unbind(args->fd);
|
||||
return ff_close(args->fd);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_ioctl(struct ff_ioctl_args *args)
|
||||
{
|
||||
return ff_ioctl(args->fd, args->com, args->data);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_fcntl(struct ff_fcntl_args *args)
|
||||
{
|
||||
return ff_fcntl(args->fd, args->cmd, args->data);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_epoll_create(struct ff_epoll_create_args *args)
|
||||
{
|
||||
DEBUG_LOG("to run ff_epoll_create, size:%d\n", args->size);
|
||||
return ff_epoll_create(args->size);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_epoll_ctl(struct ff_epoll_ctl_args *args)
|
||||
{
|
||||
DEBUG_LOG("to run ff_epoll_ctl, epfd:%d, op:%d, fd:%d\n",
|
||||
args->epfd, args->op, args->fd);
|
||||
return ff_epoll_ctl(args->epfd, args->op, args->fd,
|
||||
args->event);
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_epoll_wait(struct ff_epoll_wait_args *args)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUG_LOG("to run ff_epoll_wait, epfd:%d, maxevents:%d, timeout:%d\n",
|
||||
args->epfd, args->maxevents, args->timeout);
|
||||
ret = ff_epoll_wait(args->epfd, args->events,
|
||||
args->maxevents, args->timeout);
|
||||
|
||||
/*
|
||||
* If timeout is 0, and no event triggered,
|
||||
* no post sem, and next loop will continue to call ff_sys_epoll_wait,
|
||||
* until some event triggered
|
||||
*/
|
||||
if (args->timeout == 0 && ret == 0 && args->maxevents != 0) {
|
||||
sem_flag = 0;
|
||||
} else {
|
||||
sem_flag = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_kqueue(struct ff_kqueue_args *args)
|
||||
{
|
||||
return ff_kqueue();
|
||||
}
|
||||
|
||||
static int
|
||||
ff_sys_kevent(struct ff_kevent_args *args)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ff_kevent(args->kq, args->changelist, args->nchanges,
|
||||
args->eventlist, args->nevents, args->timeout);
|
||||
|
||||
if (args->nchanges) {
|
||||
args->nchanges = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If timeout is NULL, and no event triggered,
|
||||
* no post sem, and next loop will continue to call ff_sys_kevent,
|
||||
* until some event triggered
|
||||
*/
|
||||
if (args->timeout == NULL && ret == 0 && args->nevents != 0) {
|
||||
sem_flag = 0;
|
||||
} else {
|
||||
sem_flag = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static pid_t
|
||||
ff_sys_fork(struct ff_fork_args *args)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ff_so_handler(int ops, void *args)
|
||||
{
|
||||
DEBUG_LOG("ff_so_handler ops:%d, epoll create ops:%d\n", ops, FF_SO_EPOLL_CREATE);
|
||||
switch(ops) {
|
||||
case FF_SO_SOCKET:
|
||||
return ff_sys_socket((struct ff_socket_args *)args);
|
||||
case FF_SO_BIND:
|
||||
return ff_sys_bind((struct ff_bind_args *)args);
|
||||
case FF_SO_LISTEN:
|
||||
return ff_sys_listen((struct ff_listen_args *)args);
|
||||
case FF_SO_CONNECT:
|
||||
return ff_sys_connect((struct ff_connect_args *)args);
|
||||
case FF_SO_SHUTDOWN:
|
||||
return ff_sys_shutdown((struct ff_shutdown_args *)args);
|
||||
case FF_SO_GETSOCKNAME:
|
||||
return ff_sys_getsockname((struct ff_getsockname_args *)args);
|
||||
case FF_SO_GETPEERNAME:
|
||||
return ff_sys_getpeername((struct ff_getpeername_args *)args);
|
||||
case FF_SO_GETSOCKOPT:
|
||||
return ff_sys_getsockopt((struct ff_getsockopt_args *)args);
|
||||
case FF_SO_SETSOCKOPT:
|
||||
return ff_sys_setsockopt((struct ff_setsockopt_args *)args);
|
||||
case FF_SO_ACCEPT:
|
||||
return ff_sys_accept((struct ff_accept_args *)args);
|
||||
case FF_SO_ACCEPT4:
|
||||
return ff_sys_accept4((struct ff_accept4_args *)args);
|
||||
case FF_SO_RECV:
|
||||
return ff_sys_recv((struct ff_recv_args *)args);
|
||||
case FF_SO_RECVFROM:
|
||||
return ff_sys_recvfrom((struct ff_recvfrom_args *)args);
|
||||
case FF_SO_RECVMSG:
|
||||
return ff_sys_recvmsg((struct ff_recvmsg_args *)args);
|
||||
case FF_SO_READ:
|
||||
return ff_sys_read((struct ff_read_args *)args);
|
||||
case FF_SO_READV:
|
||||
return ff_sys_readv((struct ff_readv_args *)args);
|
||||
case FF_SO_SEND:
|
||||
return ff_sys_send((struct ff_send_args *)args);
|
||||
case FF_SO_SENDTO:
|
||||
return ff_sys_sendto((struct ff_sendto_args *)args);
|
||||
case FF_SO_SENDMSG:
|
||||
return ff_sys_sendmsg((struct ff_sendmsg_args *)args);
|
||||
case FF_SO_WRITE:
|
||||
return ff_sys_write((struct ff_write_args *)args);
|
||||
case FF_SO_WRITEV:
|
||||
return ff_sys_writev((struct ff_writev_args *)args);
|
||||
case FF_SO_CLOSE:
|
||||
return ff_sys_close((struct ff_close_args *)args);
|
||||
case FF_SO_IOCTL:
|
||||
return ff_sys_ioctl((struct ff_ioctl_args *)args);
|
||||
case FF_SO_FCNTL:
|
||||
return ff_sys_fcntl((struct ff_fcntl_args *)args);
|
||||
case FF_SO_EPOLL_CREATE:
|
||||
return ff_sys_epoll_create((struct ff_epoll_create_args *)args);
|
||||
case FF_SO_EPOLL_CTL:
|
||||
return ff_sys_epoll_ctl((struct ff_epoll_ctl_args *)args);
|
||||
case FF_SO_EPOLL_WAIT:
|
||||
return ff_sys_epoll_wait((struct ff_epoll_wait_args *)args);
|
||||
case FF_SO_KQUEUE:
|
||||
return ff_sys_kqueue((struct ff_kqueue_args *)args);
|
||||
case FF_SO_KEVENT:
|
||||
return ff_sys_kevent((struct ff_kevent_args *)args);
|
||||
case FF_SO_FORK:
|
||||
return ff_sys_fork((struct ff_fork_args *)args);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
errno = EINVAL;
|
||||
DEBUG_LOG("ff_so_handler error:%d, ops:%d\n", errno, ops);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ff_handle_socket_ops(struct ff_so_context *sc)
|
||||
{
|
||||
if (!rte_spinlock_trylock(&sc->lock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc->status != FF_SC_REQ) {
|
||||
rte_spinlock_unlock(&sc->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG("ff_handle_socket_ops sc:%p, status:%d, ops:%d\n", sc, sc->status, sc->ops);
|
||||
|
||||
errno = 0;
|
||||
sc->result = ff_so_handler(sc->ops, sc->args);
|
||||
sc->error = errno;
|
||||
DEBUG_LOG("ff_handle_socket_ops error:%d, ops:%d, result:%d\n", errno, sc->ops, sc->result);
|
||||
|
||||
if (sc->ops == FF_SO_EPOLL_WAIT || sc->ops == FF_SO_KEVENT) {
|
||||
/*DEBUG_LOG("ff_event_loop_nb:%d, ff_next_event_flag:%d\n",
|
||||
ff_event_loop_nb, ff_next_event_flag);
|
||||
if (ff_event_loop_nb > 0) {
|
||||
ff_next_event_flag = 1;
|
||||
} else {
|
||||
ff_next_event_flag = 0;
|
||||
}
|
||||
|
||||
if (sc->result > 0) {
|
||||
ff_event_loop_nb = (sc->result * EVENT_LOOP_TIMES);
|
||||
} else {
|
||||
ff_event_loop_nb = 0;
|
||||
}*/
|
||||
|
||||
if (sem_flag == 1) {
|
||||
sc->status = FF_SC_REP;
|
||||
sem_post(&sc->wait_sem);
|
||||
} else {
|
||||
// do nothing with this sc
|
||||
}
|
||||
} else {
|
||||
sc->status = FF_SC_REP;
|
||||
}
|
||||
|
||||
rte_spinlock_unlock(&sc->lock);
|
||||
}
|
||||
|
||||
void
|
||||
ff_handle_each_context()
|
||||
{
|
||||
uint16_t i, nb_handled, tmp;
|
||||
static uint64_t loop_count = 0;
|
||||
static uint64_t cur_tsc, diff_tsc, drain_tsc = 0;
|
||||
|
||||
if (unlikely(drain_tsc == 0 && ff_global_cfg.dpdk.pkt_tx_delay)) {
|
||||
drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * ff_global_cfg.dpdk.pkt_tx_delay;
|
||||
ERR_LOG("ff_global_cfg.dpdk.handle_sc_delay%d, drain_tsc:%lu\n",
|
||||
ff_global_cfg.dpdk.pkt_tx_delay, drain_tsc);
|
||||
}
|
||||
|
||||
ff_event_loop_nb = 0;
|
||||
|
||||
cur_tsc = rte_rdtsc();
|
||||
|
||||
rte_spinlock_lock(&ff_so_zone->lock);
|
||||
|
||||
assert(ff_so_zone->count >= ff_so_zone->free);
|
||||
tmp = nb_handled = ff_so_zone->count - ff_so_zone->free;
|
||||
|
||||
while(1) {
|
||||
nb_handled = tmp;
|
||||
if (nb_handled) {
|
||||
for (i = 0; i < ff_so_zone->count; i++) {
|
||||
struct ff_so_context *sc = &ff_so_zone->sc[i];
|
||||
|
||||
if ((loop_count & 1048575) == 0) {
|
||||
DEBUG_LOG("so:%p, so->count:%d,%p, sc:%p, sc->inuse:%d,%p, i:%d, nb:%d, all_nb:%d\n",
|
||||
ff_so_zone, ff_so_zone->count, &ff_so_zone->count,
|
||||
sc, ff_so_zone->inuse[i], &ff_so_zone->inuse[i], i, nb_handled, tmp);
|
||||
}
|
||||
|
||||
if (ff_so_zone->inuse[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Dirty read first, and then try to lock sc and real read. */
|
||||
if (sc->status == FF_SC_REQ) {
|
||||
ff_handle_socket_ops(sc);
|
||||
}
|
||||
|
||||
nb_handled--;
|
||||
if (!nb_handled) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if (--ff_event_loop_nb <= 0 || ff_next_event_flag == 1) {
|
||||
break;
|
||||
}*/
|
||||
diff_tsc = rte_rdtsc() - cur_tsc;
|
||||
DEBUG_LOG("cur_tsc:%lu, diff_tsc:%lu, drain_tsc:%lu\n", cur_tsc, diff_tsc, drain_tsc);
|
||||
if (diff_tsc >= drain_tsc) {
|
||||
break;
|
||||
}
|
||||
|
||||
rte_pause();
|
||||
}
|
||||
|
||||
rte_spinlock_unlock(&ff_so_zone->lock);
|
||||
|
||||
loop_count++;
|
||||
|
||||
DEBUG_LOG("loop_count:%lu, nb:%d, all_nb:%d\n",
|
||||
loop_count, nb_handled, tmp/*, ff_event_loop_nb, ff_next_event_flag*/);
|
||||
//, ff_event_loop_nb:%d, ff_next_event_flag:%d
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
#ifndef _FF_SOCKET_OPS_H_
|
||||
#define _FF_SOCKET_OPS_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <rte_atomic.h>
|
||||
#include <rte_spinlock.h>
|
||||
|
||||
/*
|
||||
* Per thread separate initialization dpdk lib and attach sc when needed,
|
||||
* such as listen same port in different threads, and socket can use in own thread.
|
||||
*
|
||||
* Otherwise, one socket can use in all threads.
|
||||
*/
|
||||
#ifdef FF_THREAD_SOCKET
|
||||
#define __FF_THREAD __thread
|
||||
#else
|
||||
#define __FF_THREAD
|
||||
#endif
|
||||
|
||||
#define ERR_LOG(fmt, ...) do { \
|
||||
printf("file:%s, line:%u, fun:%s, pid:%d, "fmt, \
|
||||
__FILE__, __LINE__, __func__, getpid(), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define DEBUG_LOG(...)
|
||||
#else
|
||||
#define DEBUG_LOG ERR_LOG
|
||||
#endif
|
||||
|
||||
/* Must be power of 2 */
|
||||
#define SOCKET_OPS_CONTEXT_MAX_NUM (1 << 5)
|
||||
|
||||
enum FF_SOCKET_OPS {
|
||||
FF_SO_SOCKET,
|
||||
FF_SO_LISTEN,
|
||||
FF_SO_BIND,
|
||||
FF_SO_CONNECT,
|
||||
FF_SO_SHUTDOWN,
|
||||
FF_SO_GETSOCKNAME,
|
||||
FF_SO_GETPEERNAME,
|
||||
FF_SO_GETSOCKOPT,
|
||||
FF_SO_SETSOCKOPT,
|
||||
FF_SO_ACCEPT,
|
||||
FF_SO_ACCEPT4, // 10
|
||||
FF_SO_RECV,
|
||||
FF_SO_RECVFROM,
|
||||
FF_SO_RECVMSG,
|
||||
FF_SO_READ,
|
||||
FF_SO_READV,
|
||||
FF_SO_SEND,
|
||||
FF_SO_SENDTO,
|
||||
FF_SO_SENDMSG,
|
||||
FF_SO_WRITE,
|
||||
FF_SO_WRITEV, // 20
|
||||
FF_SO_CLOSE,
|
||||
FF_SO_IOCTL,
|
||||
FF_SO_FCNTL,
|
||||
FF_SO_EPOLL_CREATE,
|
||||
FF_SO_EPOLL_CTL,
|
||||
FF_SO_EPOLL_WAIT,
|
||||
FF_SO_KQUEUE,
|
||||
FF_SO_KEVENT,
|
||||
FF_SO_FORK, // 29
|
||||
};
|
||||
|
||||
enum FF_SO_CONTEXT_STATUS {
|
||||
FF_SC_IDLE,
|
||||
FF_SC_REQ,
|
||||
FF_SC_REP,
|
||||
};
|
||||
|
||||
struct ff_socket_ops_zone {
|
||||
rte_spinlock_t lock;
|
||||
|
||||
/* total number of so_contex, must be power of 2 */
|
||||
uint8_t count;
|
||||
uint8_t mask;
|
||||
|
||||
/* free number of so_context */
|
||||
uint8_t free;
|
||||
|
||||
uint8_t idx;
|
||||
|
||||
/* 1 if used, else 0, most access */
|
||||
uint8_t inuse[SOCKET_OPS_CONTEXT_MAX_NUM];
|
||||
struct ff_so_context *sc;
|
||||
|
||||
uint8_t padding[16];
|
||||
} __attribute__((aligned(RTE_CACHE_LINE_SIZE)));
|
||||
|
||||
struct ff_so_context {
|
||||
/* CACHE LINE 0 */
|
||||
enum FF_SOCKET_OPS ops;
|
||||
enum FF_SO_CONTEXT_STATUS status;
|
||||
void *args;
|
||||
|
||||
rte_spinlock_t lock;
|
||||
|
||||
/* errno if failed */
|
||||
int error;
|
||||
/* result of ops processing */
|
||||
int result;
|
||||
int idx;
|
||||
|
||||
sem_t wait_sem; /* 32 bytes */
|
||||
|
||||
/* CACHE LINE 1 */
|
||||
/* listen fd, refcount.. */
|
||||
int refcount;
|
||||
} __attribute__((aligned(RTE_CACHE_LINE_SIZE)));
|
||||
|
||||
extern __FF_THREAD struct ff_socket_ops_zone *ff_so_zone;
|
||||
#ifdef FF_MULTI_SC
|
||||
extern struct ff_socket_ops_zone *ff_so_zones[SOCKET_OPS_CONTEXT_MAX_NUM];
|
||||
#endif
|
||||
|
||||
/* For primary process */
|
||||
int ff_set_max_so_context(uint16_t count);
|
||||
int ff_create_so_memzone();
|
||||
void ff_handle_each_context();
|
||||
|
||||
/* For secondary process */
|
||||
struct ff_so_context *ff_attach_so_context(int proc_id);
|
||||
void ff_detach_so_context(struct ff_so_context *context);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,197 @@
|
|||
#ifndef _FF_SYSPROTO_H_
|
||||
#define _FF_SYSPROTO_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <time.h>
|
||||
|
||||
struct ff_socket_args {
|
||||
int domain;
|
||||
int type;
|
||||
int protocol;
|
||||
};
|
||||
|
||||
struct ff_bind_args {
|
||||
int fd;
|
||||
void *addr;
|
||||
int addrlen;
|
||||
};
|
||||
|
||||
struct ff_listen_args {
|
||||
int fd;
|
||||
int backlog;
|
||||
};
|
||||
|
||||
struct ff_shutdown_args {
|
||||
int fd;
|
||||
int how;
|
||||
};
|
||||
|
||||
struct ff_getpeername_args {
|
||||
int fd;
|
||||
void *name;
|
||||
socklen_t *namelen;
|
||||
};
|
||||
|
||||
struct ff_getsockname_args {
|
||||
int fd;
|
||||
void *name;
|
||||
socklen_t *namelen;
|
||||
};
|
||||
|
||||
struct ff_setsockopt_args {
|
||||
int fd;
|
||||
int level;
|
||||
int name;
|
||||
void *optval;
|
||||
socklen_t optlen;
|
||||
};
|
||||
|
||||
struct ff_getsockopt_args {
|
||||
int fd;
|
||||
int level;
|
||||
int name;
|
||||
void *optval;
|
||||
socklen_t *optlen;
|
||||
};
|
||||
|
||||
struct ff_accept_args {
|
||||
int fd;
|
||||
void *addr;
|
||||
socklen_t *addrlen;
|
||||
};
|
||||
|
||||
struct ff_accept4_args {
|
||||
int fd;
|
||||
void *addr;
|
||||
socklen_t *addrlen;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct ff_connect_args {
|
||||
int fd;
|
||||
void *addr;
|
||||
int addrlen;
|
||||
};
|
||||
|
||||
struct ff_recv_args {
|
||||
int fd;
|
||||
void *buf;
|
||||
size_t len;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct ff_recvfrom_args {
|
||||
int fd;
|
||||
void *buf;
|
||||
size_t len;
|
||||
int flags;
|
||||
void *from;
|
||||
socklen_t *fromlen;
|
||||
};
|
||||
|
||||
struct ff_recvmsg_args {
|
||||
int fd;
|
||||
struct msghdr *msg;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct ff_read_args {
|
||||
int fd;
|
||||
void *buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct ff_readv_args {
|
||||
int fd;
|
||||
struct iovec *iov;
|
||||
int iovcnt;
|
||||
};
|
||||
|
||||
struct ff_send_args {
|
||||
int fd;
|
||||
void *buf;
|
||||
size_t len;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct ff_sendto_args {
|
||||
int fd;
|
||||
void *buf;
|
||||
size_t len;
|
||||
int flags;
|
||||
void *to;
|
||||
int tolen;
|
||||
};
|
||||
|
||||
struct ff_sendmsg_args {
|
||||
int fd;
|
||||
struct msghdr * msg;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct ff_write_args {
|
||||
int fd;
|
||||
void *buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct ff_writev_args {
|
||||
int fd;
|
||||
struct iovec *iov;
|
||||
int iovcnt;
|
||||
};
|
||||
|
||||
struct ff_close_args {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct ff_ioctl_args {
|
||||
int fd;
|
||||
unsigned long com;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct ff_fcntl_args {
|
||||
int fd;
|
||||
int cmd;
|
||||
long data;
|
||||
};
|
||||
|
||||
struct ff_epoll_create_args {
|
||||
int size;
|
||||
};
|
||||
|
||||
struct ff_epoll_ctl_args {
|
||||
int epfd;
|
||||
int op;
|
||||
int fd;
|
||||
struct epoll_event *event;
|
||||
};
|
||||
|
||||
struct ff_epoll_wait_args {
|
||||
int epfd;
|
||||
struct epoll_event *events;
|
||||
int maxevents;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
struct ff_kqueue_args {
|
||||
|
||||
};
|
||||
|
||||
struct ff_kevent_args {
|
||||
int kq;
|
||||
struct kevent *changelist;
|
||||
int nchanges;
|
||||
struct kevent *eventlist;
|
||||
int nevents;
|
||||
struct timespec *timeout;
|
||||
};
|
||||
|
||||
struct ff_fork_args {
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
#include "ff_api.h"
|
||||
#include "ff_socket_ops.h"
|
||||
|
||||
#define WORKERS 32
|
||||
|
||||
int
|
||||
loop(void *arg)
|
||||
{
|
||||
ff_handle_each_context();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char * argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ff_init(argc, argv);
|
||||
|
||||
ret = ff_set_max_so_context(WORKERS);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ff_create_so_memzone();
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ERR_LOG("ff_create_so_memzone successful\n");
|
||||
|
||||
ff_run(loop, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
//#include "ff_config.h"
|
||||
//#include "ff_api.h"
|
||||
#include "ff_event.h"
|
||||
#include "ff_adapter.h"
|
||||
#include "ff_hook_syscall.h"
|
||||
|
||||
pthread_t hworker;
|
||||
|
||||
#define MAX_EVENTS 512
|
||||
|
||||
/* kevent set */
|
||||
struct kevent kevSet;
|
||||
/* events */
|
||||
struct kevent events[MAX_EVENTS];
|
||||
/* kq */
|
||||
int kq;
|
||||
int sockfd;
|
||||
|
||||
struct timespec timeout = {0, 100000};
|
||||
|
||||
static int exit_flag = 0;
|
||||
|
||||
char html[] =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Server: F-Stack\r\n"
|
||||
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: 438\r\n"
|
||||
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
|
||||
"Connection: keep-alive\r\n"
|
||||
"Accept-Ranges: bytes\r\n"
|
||||
"\r\n"
|
||||
"<!DOCTYPE html>\r\n"
|
||||
"<html>\r\n"
|
||||
"<head>\r\n"
|
||||
"<title>Welcome to F-Stack!</title>\r\n"
|
||||
"<style>\r\n"
|
||||
" body { \r\n"
|
||||
" width: 35em;\r\n"
|
||||
" margin: 0 auto; \r\n"
|
||||
" font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
|
||||
" }\r\n"
|
||||
"</style>\r\n"
|
||||
"</head>\r\n"
|
||||
"<body>\r\n"
|
||||
"<h1>Welcome to F-Stack!</h1>\r\n"
|
||||
"\r\n"
|
||||
"<p>For online documentation and support please refer to\r\n"
|
||||
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
|
||||
"\r\n"
|
||||
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
|
||||
"</body>\r\n"
|
||||
"</html>";
|
||||
|
||||
void sig_term(int sig)
|
||||
{
|
||||
printf("we caught signal %d, to exit helloworld\n", sig);
|
||||
exit_flag = 1;
|
||||
alarm_event_sem();
|
||||
return;
|
||||
}
|
||||
|
||||
void *loop(void *arg)
|
||||
{
|
||||
/* Wait for events to happen */
|
||||
while (!exit_flag) {
|
||||
/*
|
||||
* If timeout is NULL, must call alarm_event_sem();
|
||||
*/
|
||||
int nevents = kevent(kq, NULL, 0, events, MAX_EVENTS, &timeout);
|
||||
int i;
|
||||
|
||||
if (nevents <= 0) {
|
||||
if (nevents) {
|
||||
printf("ff_kevent failed:%d, %s\n", errno,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
//usleep(100);
|
||||
//sleep(1);
|
||||
}
|
||||
//printf("get nevents:%d\n", nevents);
|
||||
|
||||
for (i = 0; i < nevents; ++i) {
|
||||
struct kevent event = events[i];
|
||||
int clientfd = (int)event.ident;
|
||||
|
||||
/* Handle disconnect */
|
||||
if (event.flags & EV_EOF) {
|
||||
/* Simply close socket */
|
||||
close(clientfd);
|
||||
} else if (clientfd == sockfd) {
|
||||
int available = (int)event.data;
|
||||
do {
|
||||
int nclientfd = accept(clientfd, NULL, NULL);
|
||||
if (nclientfd < 0) {
|
||||
printf("ff_accept failed:%d, %s\n", errno,
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add to event list */
|
||||
EV_SET(&kevSet, nclientfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
|
||||
if(kevent(kq, &kevSet, 1, NULL, 0, NULL) < 0) {
|
||||
printf("ff_kevent error:%d, %s\n", errno,
|
||||
strerror(errno));
|
||||
close(nclientfd);
|
||||
break;
|
||||
}
|
||||
|
||||
available--;
|
||||
} while (available);
|
||||
} else if (event.filter == EVFILT_READ) {
|
||||
char buf[256];
|
||||
ssize_t readlen = read(clientfd, buf, sizeof(buf));
|
||||
ssize_t writelen = write(clientfd, html, sizeof(html) - 1);
|
||||
if (writelen < 0){
|
||||
printf("ff_write failed, readlen:%lu, writelen:%lu, :%d, %s\n",
|
||||
readlen, writelen, errno, strerror(errno));
|
||||
close(clientfd);
|
||||
}
|
||||
} else {
|
||||
printf("unknown event: %8.8X\n", event.flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
signal(SIGINT, sig_term);
|
||||
signal(SIGTERM, sig_term);
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
printf("sockfd:%d\n", sockfd);
|
||||
if (sockfd < 0) {
|
||||
printf("ff_socket failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
|
||||
return -1;;
|
||||
}
|
||||
|
||||
/* Set non blocking */
|
||||
int on = 1;
|
||||
ioctl(sockfd, FIONBIO, &on);
|
||||
|
||||
struct sockaddr_in my_addr;
|
||||
bzero(&my_addr, sizeof(my_addr));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(80);
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
int ret = bind(sockfd, (const struct sockaddr *)&my_addr, sizeof(my_addr));
|
||||
if (ret < 0) {
|
||||
printf("ff_bind failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = listen(sockfd, MAX_EVENTS);
|
||||
if (ret < 0) {
|
||||
printf("ff_listen failed, sockfd:%d, errno:%d, %s\n", sockfd, errno, strerror(errno));
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kq = kqueue();
|
||||
printf("kq:%d\n", kq);
|
||||
if (kq < 0) {
|
||||
printf("ff_kqueue failed, errno:%d, %s\n", errno, strerror(errno));
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kevSet, sockfd, EVFILT_READ, EV_ADD, 0, MAX_EVENTS, NULL);
|
||||
/* Update kqueue */
|
||||
ret = kevent(kq, &kevSet, 1, NULL, 0, &timeout);
|
||||
if (ret < 0) {
|
||||
printf("kevent failed\n");
|
||||
close(kq);
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pthread_create(&hworker, NULL, loop, NULL) < 0) {
|
||||
printf("create loop thread failed., errno:%d/%s\n",
|
||||
errno, strerror(errno));
|
||||
close(kq);
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_join(hworker, NULL);
|
||||
|
||||
close(kq);
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define MAX_WORKERS 128
|
||||
pthread_t hworker[MAX_WORKERS];
|
||||
|
||||
#define MAX_EVENTS 512
|
||||
struct epoll_event ev;
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
int epfd;
|
||||
int sockfd;
|
||||
|
||||
static int exit_flag = 0;
|
||||
|
||||
char html[] =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Server: F-Stack\r\n"
|
||||
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: 438\r\n"
|
||||
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
|
||||
"Connection: keep-alive\r\n"
|
||||
"Accept-Ranges: bytes\r\n"
|
||||
"\r\n"
|
||||
"<!DOCTYPE html>\r\n"
|
||||
"<html>\r\n"
|
||||
"<head>\r\n"
|
||||
"<title>Welcome to F-Stack!</title>\r\n"
|
||||
"<style>\r\n"
|
||||
" body { \r\n"
|
||||
" width: 35em;\r\n"
|
||||
" margin: 0 auto; \r\n"
|
||||
" font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
|
||||
" }\r\n"
|
||||
"</style>\r\n"
|
||||
"</head>\r\n"
|
||||
"<body>\r\n"
|
||||
"<h1>Welcome to F-Stack!</h1>\r\n"
|
||||
"\r\n"
|
||||
"<p>For online documentation and support please refer to\r\n"
|
||||
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
|
||||
"\r\n"
|
||||
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
|
||||
"</body>\r\n"
|
||||
"</html>";
|
||||
|
||||
void sig_term(int sig)
|
||||
{
|
||||
printf("we caught signal %d, to exit helloworld\n", sig);
|
||||
exit_flag = 1;
|
||||
//alarm_event_sem();
|
||||
return;
|
||||
}
|
||||
|
||||
void *loop(void *arg)
|
||||
{
|
||||
/* Wait for events to happen */
|
||||
while (!exit_flag) {
|
||||
/*
|
||||
* If not call alarm_event_sem, and epoll_wait timeout is 0,
|
||||
* it can't exit normal, so timeout can't set to 0.
|
||||
*/
|
||||
int nevents = epoll_wait(epfd, events, MAX_EVENTS, 100);
|
||||
int i;
|
||||
|
||||
if (nevents <= 0) {
|
||||
if (nevents) {
|
||||
printf("hello world epoll wait ret %d, errno:%d, %s\n",
|
||||
nevents, errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
//usleep(100);
|
||||
sleep(1);
|
||||
}
|
||||
//printf("get nevents:%d\n", nevents);
|
||||
|
||||
for (i = 0; i < nevents; ++i) {
|
||||
/* Handle new connect */
|
||||
if (events[i].data.fd == sockfd) {
|
||||
while (1) {
|
||||
int nclientfd = accept(sockfd, NULL, NULL);
|
||||
printf("accept sockfd:%d, nclientfd:%d, errono:%d/%s\n", sockfd, nclientfd, errno, strerror(errno));
|
||||
if (nclientfd < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add to event list */
|
||||
ev.data.fd = nclientfd;
|
||||
ev.events = EPOLLIN;
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, nclientfd, &ev) != 0) {
|
||||
printf("ff_epoll_ctl failed:%d, %s\n",
|
||||
errno, strerror(errno));
|
||||
close(nclientfd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (events[i].events & EPOLLERR ) {
|
||||
/* Simply close socket */
|
||||
epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
|
||||
close(events[i].data.fd);
|
||||
} else if (events[i].events & EPOLLIN) {
|
||||
char buf[256];
|
||||
size_t readlen = read( events[i].data.fd, buf, sizeof(buf));
|
||||
if(readlen > 0) {
|
||||
write( events[i].data.fd, html, sizeof(html) - 1);
|
||||
} else {
|
||||
epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
|
||||
close(events[i].data.fd);
|
||||
}
|
||||
} else {
|
||||
printf("unknown event: %d:%8.8X\n", i, events[i].events);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int i, worker_num = 1;
|
||||
|
||||
signal(SIGINT, sig_term);
|
||||
signal(SIGTERM, sig_term);
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
printf("sockfd:%d\n", sockfd);
|
||||
if (sockfd < 0) {
|
||||
printf("ff_socket failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int on = 1;
|
||||
ioctl(sockfd, FIONBIO, &on);
|
||||
|
||||
struct sockaddr_in my_addr;
|
||||
bzero(&my_addr, sizeof(my_addr));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(80);
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
int ret = bind(sockfd, (const struct sockaddr *)&my_addr, sizeof(my_addr));
|
||||
if (ret < 0) {
|
||||
printf("ff_bind failed\n");
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = listen(sockfd, MAX_EVENTS);
|
||||
if (ret < 0) {
|
||||
printf("ff_listen failed\n");
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
epfd = epoll_create(512);
|
||||
printf("epfd:%d\n", epfd);
|
||||
if (epfd <= 0) {
|
||||
printf("ff_epoll_create failed, errno:%d, %s\n",
|
||||
errno, strerror(errno));
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ev.data.fd = sockfd;
|
||||
ev.events = EPOLLIN;
|
||||
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
|
||||
if (ret < 0) {
|
||||
printf("ff_listen failed\n");
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < worker_num; i++) {
|
||||
if(pthread_create(&hworker[i], NULL, loop, (void *)&i) < 0) {
|
||||
printf("create loop thread failed., errno:%d/%s\n",
|
||||
errno, strerror(errno));
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < worker_num; i++) {
|
||||
pthread_join(hworker[i], NULL);
|
||||
}
|
||||
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define SOCK_FSTACK 0x01000000
|
||||
#define SOCK_KERNEL 0x02000000
|
||||
|
||||
#define MAX_WORKERS 128
|
||||
pthread_t hworker[MAX_WORKERS];
|
||||
|
||||
#define MAX_EVENTS 512
|
||||
struct epoll_event ev;
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
int epfd;
|
||||
int sockfd, sockfd_kernel;
|
||||
|
||||
static int exit_flag = 0;
|
||||
|
||||
char html[] =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Server: F-Stack\r\n"
|
||||
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: 438\r\n"
|
||||
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
|
||||
"Connection: keep-alive\r\n"
|
||||
"Accept-Ranges: bytes\r\n"
|
||||
"\r\n"
|
||||
"<!DOCTYPE html>\r\n"
|
||||
"<html>\r\n"
|
||||
"<head>\r\n"
|
||||
"<title>Welcome to F-Stack!</title>\r\n"
|
||||
"<style>\r\n"
|
||||
" body { \r\n"
|
||||
" width: 35em;\r\n"
|
||||
" margin: 0 auto; \r\n"
|
||||
" font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
|
||||
" }\r\n"
|
||||
"</style>\r\n"
|
||||
"</head>\r\n"
|
||||
"<body>\r\n"
|
||||
"<h1>Welcome to F-Stack!</h1>\r\n"
|
||||
"\r\n"
|
||||
"<p>For online documentation and support please refer to\r\n"
|
||||
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
|
||||
"\r\n"
|
||||
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
|
||||
"</body>\r\n"
|
||||
"</html>";
|
||||
|
||||
void sig_term(int sig)
|
||||
{
|
||||
printf("we caught signal %d, to exit helloworld\n", sig);
|
||||
exit_flag = 1;
|
||||
//alarm_event_sem();
|
||||
return;
|
||||
}
|
||||
|
||||
void *loop(void *arg)
|
||||
{
|
||||
/* Wait for events to happen */
|
||||
while (!exit_flag) {
|
||||
/*
|
||||
* If not call alarm_event_sem, and epoll_wait timeout is 0,
|
||||
* it can't exit normal, so timeout can't set to 0.
|
||||
*/
|
||||
int nevents = epoll_wait(epfd, events, MAX_EVENTS, -1);
|
||||
int i;
|
||||
|
||||
if (nevents <= 0) {
|
||||
if (nevents) {
|
||||
printf("hello world epoll wait ret %d, errno:%d, %s\n",
|
||||
nevents, errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
usleep(100);
|
||||
//sleep(1);
|
||||
}
|
||||
//printf("get nevents:%d\n", nevents);
|
||||
|
||||
for (i = 0; i < nevents; ++i) {
|
||||
/* Handle new connect */
|
||||
if (events[i].data.fd == sockfd || events[i].data.fd == sockfd_kernel) {
|
||||
while (1) {
|
||||
int nclientfd = accept(events[i].data.fd, NULL, NULL);
|
||||
printf("accept sockfd(_kernel):%d, nclientfd:%d, errono:%d/%s\n", events[i].data.fd, nclientfd, errno, strerror(errno));
|
||||
if (nclientfd < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add to event list */
|
||||
ev.data.fd = nclientfd;
|
||||
ev.events = EPOLLIN;
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, nclientfd, &ev) != 0) {
|
||||
printf("ff_epoll_ctl failed:%d, %s\n",
|
||||
errno, strerror(errno));
|
||||
close(nclientfd);
|
||||
break;
|
||||
}
|
||||
if (events[i].data.fd == sockfd_kernel) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (events[i].events & EPOLLERR ) {
|
||||
/* Simply close socket */
|
||||
epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
|
||||
close(events[i].data.fd);
|
||||
} else if (events[i].events & EPOLLIN) {
|
||||
char buf[256];
|
||||
size_t readlen = read( events[i].data.fd, buf, sizeof(buf));
|
||||
if(readlen > 0) {
|
||||
write( events[i].data.fd, html, sizeof(html) - 1);
|
||||
} else {
|
||||
epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
|
||||
close(events[i].data.fd);
|
||||
}
|
||||
} else {
|
||||
printf("unknown event: %d:%8.8X\n", i, events[i].events);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int i, worker_num = 1;
|
||||
|
||||
signal(SIGINT, sig_term);
|
||||
signal(SIGTERM, sig_term);
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
printf("sockfd:%d\n", sockfd);
|
||||
if (sockfd < 0) {
|
||||
printf("ff_socket failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int on = 1;
|
||||
ioctl(sockfd, FIONBIO, &on);
|
||||
|
||||
struct sockaddr_in my_addr;
|
||||
bzero(&my_addr, sizeof(my_addr));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(80);
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
int ret = bind(sockfd, (const struct sockaddr *)&my_addr, sizeof(my_addr));
|
||||
if (ret < 0) {
|
||||
printf("ff_bind failed\n");
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = listen(sockfd, MAX_EVENTS);
|
||||
if (ret < 0) {
|
||||
printf("ff_listen failed\n");
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockfd_kernel = socket(AF_INET, SOCK_STREAM | SOCK_KERNEL, 0);
|
||||
printf("sockfd_kernel:%d\n", sockfd_kernel);
|
||||
if (sockfd_kernel < 0) {
|
||||
printf("ff_socket failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bzero(&my_addr, sizeof(my_addr));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(80);
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
ret = bind(sockfd_kernel, (const struct sockaddr *)&my_addr, sizeof(my_addr));
|
||||
if (ret < 0) {
|
||||
printf("ff_bind failed\n");
|
||||
close(sockfd);
|
||||
close(sockfd_kernel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = listen(sockfd_kernel, MAX_EVENTS);
|
||||
if (ret < 0) {
|
||||
printf("ff_listen failed\n");
|
||||
close(sockfd);
|
||||
close(sockfd_kernel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
epfd = epoll_create(512);
|
||||
printf("epfd:%d\n", epfd);
|
||||
if (epfd <= 0) {
|
||||
printf("ff_epoll_create failed, errno:%d, %s\n",
|
||||
errno, strerror(errno));
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ev.data.fd = sockfd;
|
||||
ev.events = EPOLLIN;
|
||||
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
|
||||
if (ret < 0) {
|
||||
printf("ff_listen failed\n");
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
close(sockfd_kernel);
|
||||
return -1;
|
||||
}
|
||||
ev.data.fd = sockfd_kernel;
|
||||
ev.events = EPOLLIN;
|
||||
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd_kernel, &ev);
|
||||
if (ret < 0) {
|
||||
printf("ff_listen failed\n");
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
close(sockfd_kernel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < worker_num; i++) {
|
||||
if(pthread_create(&hworker[i], NULL, loop, (void *)&i) < 0) {
|
||||
printf("create loop thread failed., errno:%d/%s\n",
|
||||
errno, strerror(errno));
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
close(sockfd_kernel);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < worker_num; i++) {
|
||||
pthread_join(hworker[i], NULL);
|
||||
}
|
||||
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
close(sockfd_kernel);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define MAX_WORKERS 128
|
||||
pthread_t hworker[MAX_WORKERS];
|
||||
pthread_spinlock_t worker_lock;
|
||||
#define MAX_EVENTS 512
|
||||
|
||||
static int exit_flag = 0;
|
||||
|
||||
char html[] =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Server: F-Stack\r\n"
|
||||
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: 438\r\n"
|
||||
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
|
||||
"Connection: keep-alive\r\n"
|
||||
"Accept-Ranges: bytes\r\n"
|
||||
"\r\n"
|
||||
"<!DOCTYPE html>\r\n"
|
||||
"<html>\r\n"
|
||||
"<head>\r\n"
|
||||
"<title>Welcome to F-Stack!</title>\r\n"
|
||||
"<style>\r\n"
|
||||
" body { \r\n"
|
||||
" width: 35em;\r\n"
|
||||
" margin: 0 auto; \r\n"
|
||||
" font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
|
||||
" }\r\n"
|
||||
"</style>\r\n"
|
||||
"</head>\r\n"
|
||||
"<body>\r\n"
|
||||
"<h1>Welcome to F-Stack!</h1>\r\n"
|
||||
"\r\n"
|
||||
"<p>For online documentation and support please refer to\r\n"
|
||||
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
|
||||
"\r\n"
|
||||
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
|
||||
"</body>\r\n"
|
||||
"</html>";
|
||||
|
||||
void sig_term(int sig)
|
||||
{
|
||||
printf("we caught signal %d, to exit helloworld\n", sig);
|
||||
exit_flag = 1;
|
||||
//alarm_event_sem();
|
||||
return;
|
||||
}
|
||||
|
||||
#define SOCK_FSTACK 0x01000000
|
||||
#define SOCK_KERNEL 0x02000000
|
||||
void *loop(void *arg)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
int epfd;
|
||||
int sockfd;
|
||||
int thread_id;
|
||||
|
||||
thread_id = *(int *)arg;
|
||||
printf("start thread %d\n", thread_id);
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM | SOCK_FSTACK, 0);
|
||||
printf("thread %d, sockfd:%d\n", thread_id, sockfd);
|
||||
if (sockfd < 0) {
|
||||
printf("thread %d, ff_socket failed\n", thread_id);
|
||||
pthread_spin_unlock(&worker_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* socket will init adapter,so unlock after socket */
|
||||
pthread_spin_unlock(&worker_lock);
|
||||
|
||||
int on = 1;
|
||||
//ioctl(sockfd, FIONBIO, &on);
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) {
|
||||
printf("thread %d, setsockopt SO_REUSEPORT failed\n", thread_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sockaddr_in my_addr;
|
||||
bzero(&my_addr, sizeof(my_addr));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(80);
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
int ret = bind(sockfd, (const struct sockaddr *)&my_addr, sizeof(my_addr));
|
||||
if (ret < 0) {
|
||||
printf("thread %d, ff_bind failed\n", thread_id);
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = listen(sockfd, MAX_EVENTS);
|
||||
if (ret < 0) {
|
||||
printf("thread %d, ff_listen failed\n", thread_id);
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
epfd = epoll_create(512|SOCK_FSTACK);
|
||||
printf("thread %d, epfd:%d\n", thread_id, epfd);
|
||||
if (epfd <= 0) {
|
||||
printf("thread %d, ff_epoll_create failed, errno:%d, %s\n",
|
||||
thread_id, errno, strerror(errno));
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
ev.data.fd = sockfd;
|
||||
ev.events = EPOLLIN;
|
||||
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
|
||||
if (ret < 0) {
|
||||
printf("ff_listen failed\n");
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Wait for events to happen */
|
||||
while (!exit_flag) {
|
||||
/*
|
||||
* If not call alarm_event_sem, and epoll_wait timeout is 0,
|
||||
* it can't exit normal, so timeout can't set to 0.
|
||||
*/
|
||||
int nevents = epoll_wait(epfd, events, MAX_EVENTS, 100);
|
||||
int i;
|
||||
|
||||
if (nevents <= 0) {
|
||||
if (nevents) {
|
||||
printf("thread %d, hello world epoll wait ret %d, errno:%d, %s\n",
|
||||
thread_id, nevents, errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
//usleep(100);
|
||||
//sleep(1);
|
||||
}
|
||||
/*if (nevents > 100) {
|
||||
printf("error event nb:%d, to exit\n", nevents);
|
||||
break;
|
||||
}*/
|
||||
//printf("thread %d, get nevents:%d\n", thread_id, nevents);
|
||||
|
||||
for (i = 0; i < nevents; ++i) {
|
||||
/* Handle new connect */
|
||||
if (events[i].data.fd == sockfd) {
|
||||
//while (1) {
|
||||
int nclientfd = accept(sockfd, NULL, NULL);
|
||||
if (nclientfd < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add to event list */
|
||||
ev.data.fd = nclientfd;
|
||||
ev.events = EPOLLIN;
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, nclientfd, &ev) != 0) {
|
||||
printf("thread %d, ff_epoll_ctl failed:%d, %s\n",
|
||||
thread_id, errno, strerror(errno));
|
||||
close(nclientfd);
|
||||
break;
|
||||
}
|
||||
//}
|
||||
} else {
|
||||
if (events[i].events & EPOLLERR ) {
|
||||
/* Simply close socket */
|
||||
epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
|
||||
close(events[i].data.fd);
|
||||
} else if (events[i].events & EPOLLIN) {
|
||||
char buf[256];
|
||||
size_t readlen = read( events[i].data.fd, buf, sizeof(buf));
|
||||
if(readlen > 0) {
|
||||
write( events[i].data.fd, html, sizeof(html) - 1);
|
||||
} else {
|
||||
epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
|
||||
close(events[i].data.fd);
|
||||
}
|
||||
} else {
|
||||
printf("thread %d, unknown event: %8.8X\n", thread_id, events[i].events);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(epfd);
|
||||
close(sockfd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int i, worker_num;
|
||||
|
||||
signal(SIGINT, sig_term);
|
||||
signal(SIGTERM, sig_term);
|
||||
|
||||
if (argc == 1) {
|
||||
worker_num = 1;
|
||||
} else {
|
||||
worker_num = atoi(argv[1]);
|
||||
}
|
||||
printf("to init %d workers.\n", worker_num);
|
||||
|
||||
pthread_spin_init(&worker_lock, PTHREAD_PROCESS_PRIVATE);
|
||||
pthread_spin_lock(&worker_lock);
|
||||
|
||||
for (i = 0; i < worker_num; i++) {
|
||||
if(pthread_create(&hworker[i], NULL, loop, (void *)&i) < 0) {
|
||||
printf("create loop thread failed., errno:%d/%s\n",
|
||||
errno, strerror(errno));
|
||||
pthread_spin_unlock(&worker_lock);
|
||||
pthread_spin_destroy(&worker_lock);
|
||||
return -1;
|
||||
}
|
||||
if (i > 0) {
|
||||
cpu_set_t cpuinfo;
|
||||
int lcore_id = 2 + i;
|
||||
|
||||
CPU_ZERO(&cpuinfo);
|
||||
CPU_SET_S(lcore_id, sizeof(cpuinfo), &cpuinfo);
|
||||
if(0 != pthread_setaffinity_np(hworker[i], sizeof(cpu_set_t), &cpuinfo))
|
||||
{
|
||||
printf("set affinity recver faild\n");
|
||||
exit(0);
|
||||
}
|
||||
printf("set affinity recver sucssed, thread:%d, lcore_id:%d\n", i, lcore_id);
|
||||
}
|
||||
pthread_spin_lock(&worker_lock);
|
||||
//sleep(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < worker_num; i++) {
|
||||
pthread_join(hworker[i], NULL);
|
||||
}
|
||||
|
||||
pthread_spin_destroy(&worker_lock);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
//#include "ff_config.h"
|
||||
//#include "ff_api.h"
|
||||
#include "ff_event.h"
|
||||
#include "ff_adapter.h"
|
||||
#include "ff_hook_syscall.h"
|
||||
|
||||
#define MAX_WORKERS 128
|
||||
pthread_t hworker[MAX_WORKERS];
|
||||
pthread_spinlock_t worker_lock;
|
||||
#define MAX_EVENTS 512
|
||||
|
||||
/* 100 ms */
|
||||
struct timespec timeout = {0, 100000000};
|
||||
|
||||
static int exit_flag = 0;
|
||||
|
||||
char html[] =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Server: F-Stack\r\n"
|
||||
"Date: Sat, 25 Feb 2017 09:26:33 GMT\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: 438\r\n"
|
||||
"Last-Modified: Tue, 21 Feb 2017 09:44:03 GMT\r\n"
|
||||
"Connection: keep-alive\r\n"
|
||||
"Accept-Ranges: bytes\r\n"
|
||||
"\r\n"
|
||||
"<!DOCTYPE html>\r\n"
|
||||
"<html>\r\n"
|
||||
"<head>\r\n"
|
||||
"<title>Welcome to F-Stack!</title>\r\n"
|
||||
"<style>\r\n"
|
||||
" body { \r\n"
|
||||
" width: 35em;\r\n"
|
||||
" margin: 0 auto; \r\n"
|
||||
" font-family: Tahoma, Verdana, Arial, sans-serif;\r\n"
|
||||
" }\r\n"
|
||||
"</style>\r\n"
|
||||
"</head>\r\n"
|
||||
"<body>\r\n"
|
||||
"<h1>Welcome to F-Stack!</h1>\r\n"
|
||||
"\r\n"
|
||||
"<p>For online documentation and support please refer to\r\n"
|
||||
"<a href=\"http://F-Stack.org/\">F-Stack.org</a>.<br/>\r\n"
|
||||
"\r\n"
|
||||
"<p><em>Thank you for using F-Stack.</em></p>\r\n"
|
||||
"</body>\r\n"
|
||||
"</html>";
|
||||
|
||||
void sig_term(int sig)
|
||||
{
|
||||
printf("we caught signal %d, to exit helloworld\n", sig);
|
||||
exit_flag = 1;
|
||||
//alarm_event_sem();
|
||||
return;
|
||||
}
|
||||
|
||||
void *loop(void *arg)
|
||||
{
|
||||
/* kevent set */
|
||||
struct kevent kevSet;
|
||||
/* events */
|
||||
struct kevent events[MAX_EVENTS];
|
||||
/* kq */
|
||||
int kq;
|
||||
int sockfd;
|
||||
|
||||
int thread_id;
|
||||
|
||||
thread_id = *(int *)arg;
|
||||
printf("start thread %d\n", thread_id);
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
printf("thread %d, sockfd:%d\n", thread_id, sockfd);
|
||||
if (sockfd < 0) {
|
||||
printf("thread %d, ff_socket failed\n", thread_id);
|
||||
pthread_spin_unlock(&worker_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* socket will init adapter,so unlock after socket */
|
||||
pthread_spin_unlock(&worker_lock);
|
||||
|
||||
int on = 1;
|
||||
ioctl(sockfd, FIONBIO, &on);
|
||||
|
||||
struct sockaddr_in my_addr;
|
||||
bzero(&my_addr, sizeof(my_addr));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(80);
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
int ret = bind(sockfd, (const struct sockaddr *)&my_addr, sizeof(my_addr));
|
||||
if (ret < 0) {
|
||||
printf("thread %d, ff_bind failed\n", thread_id);
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = listen(sockfd, MAX_EVENTS);
|
||||
if (ret < 0) {
|
||||
printf("thread %d, ff_listen failed\n", thread_id);
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
kq = kqueue();
|
||||
printf("thread %d, kq:%d\n", thread_id, kq);
|
||||
if (kq < 0) {
|
||||
printf("thread %d, ff_kqueue failed, errno:%d, %s\n", thread_id, errno, strerror(errno));
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EV_SET(&kevSet, sockfd, EVFILT_READ, EV_ADD, 0, MAX_EVENTS, NULL);
|
||||
/* Update kqueue */
|
||||
ret = kevent(kq, &kevSet, 1, NULL, 0, &timeout);
|
||||
if (ret < 0) {
|
||||
printf("thread %d, kevent failed\n", thread_id);
|
||||
close(kq);
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Wait for events to happen */
|
||||
while (!exit_flag) {
|
||||
/*
|
||||
* If not call alarm_event_sem, and epoll_wait timeout is NULL,
|
||||
* it can't exit normal, so timeout can't set to NULL.
|
||||
*/
|
||||
int nevents = kevent(kq, NULL, 0, events, MAX_EVENTS, &timeout);
|
||||
int i;
|
||||
|
||||
if (nevents <= 0) {
|
||||
if (nevents) {
|
||||
printf("thread %d, ff_kevent failed:%d, %s\n", thread_id, errno,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
//usleep(100);
|
||||
//sleep(1);
|
||||
}
|
||||
//printf("thread %d, get nevents:%d\n", thread_id, nevents);
|
||||
|
||||
for (i = 0; i < nevents; ++i) {
|
||||
struct kevent event = events[i];
|
||||
int clientfd = (int)event.ident;
|
||||
|
||||
/* Handle disconnect */
|
||||
if (event.flags & EV_EOF) {
|
||||
/* Simply close socket */
|
||||
close(clientfd);
|
||||
} else if (clientfd == sockfd) {
|
||||
int available = (int)event.data;
|
||||
do {
|
||||
int nclientfd = accept(clientfd, NULL, NULL);
|
||||
if (nclientfd < 0) {
|
||||
printf("thread %d, ff_accept failed:%d, %s\n", thread_id, errno,
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add to event list */
|
||||
EV_SET(&kevSet, nclientfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
|
||||
if(kevent(kq, &kevSet, 1, NULL, 0, NULL) < 0) {
|
||||
printf("thread %d, ff_kevent error:%d, %s\n", thread_id, errno,
|
||||
strerror(errno));
|
||||
close(nclientfd);
|
||||
break;
|
||||
}
|
||||
|
||||
available--;
|
||||
} while (available);
|
||||
} else if (event.filter == EVFILT_READ) {
|
||||
char buf[256];
|
||||
ssize_t readlen = read(clientfd, buf, sizeof(buf));
|
||||
ssize_t writelen = write(clientfd, html, sizeof(html) - 1);
|
||||
if (writelen < 0){
|
||||
printf("thread %d, ff_write failed, readlen:%lu, writelen:%lu, :%d, %s\n",
|
||||
thread_id, readlen, writelen, errno, strerror(errno));
|
||||
close(clientfd);
|
||||
}
|
||||
} else {
|
||||
printf("thread %d, unknown event: %d:%8.8X\n", thread_id, i, event.flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(kq);
|
||||
close(sockfd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int i, worker_num;
|
||||
|
||||
signal(SIGINT, sig_term);
|
||||
signal(SIGTERM, sig_term);
|
||||
|
||||
if (argc == 1) {
|
||||
worker_num = 1;
|
||||
} else {
|
||||
worker_num = atoi(argv[1]);
|
||||
}
|
||||
printf("to init %d workers.\n", worker_num);
|
||||
|
||||
pthread_spin_init(&worker_lock, PTHREAD_PROCESS_PRIVATE);
|
||||
pthread_spin_lock(&worker_lock);
|
||||
|
||||
for (i = 0; i < worker_num; i++) {
|
||||
if(pthread_create(&hworker[i], NULL, loop, (void *)&i) < 0) {
|
||||
printf("create loop thread failed., errno:%d/%s\n",
|
||||
errno, strerror(errno));
|
||||
pthread_spin_unlock(&worker_lock);
|
||||
pthread_spin_destroy(&worker_lock);
|
||||
return -1;
|
||||
}
|
||||
if (i > 0) {
|
||||
cpu_set_t cpuinfo;
|
||||
int lcore_id = 2 + i;
|
||||
|
||||
CPU_ZERO(&cpuinfo);
|
||||
CPU_SET_S(lcore_id, sizeof(cpuinfo), &cpuinfo);
|
||||
if(0 != pthread_setaffinity_np(hworker[i], sizeof(cpu_set_t), &cpuinfo))
|
||||
{
|
||||
printf("set affinity recver faild\n");
|
||||
exit(0);
|
||||
}
|
||||
printf("set affinity recver sucssed, thread:%d, lcore_id:%d\n", i, lcore_id);
|
||||
}
|
||||
pthread_spin_lock(&worker_lock);
|
||||
}
|
||||
|
||||
for (i = 0; i < worker_num; i++) {
|
||||
pthread_join(hworker[i], NULL);
|
||||
}
|
||||
|
||||
pthread_spin_destroy(&worker_lock);
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -10,7 +10,7 @@ endif
|
|||
|
||||
PKGCONF ?= pkg-config
|
||||
|
||||
CFLAGS += -O -gdwarf-2 $(shell $(PKGCONF) --cflags libdpdk)
|
||||
CFLAGS += -O0 -g -gdwarf-2 $(shell $(PKGCONF) --cflags libdpdk)
|
||||
|
||||
LIBS+= $(shell $(PKGCONF) --static --libs libdpdk)
|
||||
LIBS+= -L${FF_PATH}/lib -Wl,--whole-archive,-lfstack,--no-whole-archive
|
||||
|
|
Loading…
Reference in New Issue