Skip to content

add fork support, like linux kernel, every process has one freebsd struct thread #887

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions adapter/syscall/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ endif
# Use for some scenarios similar to Nginx.
#FF_KERNEL_EVENT=1

# If enable FF_USE_THREAD_STRUCT_HANDLE, every ff_so_context has one struct thread handle in fstack, fork will be supported
# like linux kernel.
#FF_USE_THREAD_STRUCT_HANDLE=1

PKGCONF ?= pkg-config

ifndef DEBUG
Expand All @@ -49,6 +53,10 @@ ifdef FF_PRELOAD_POLLING_MODE
CFLAGS+= -DFF_PRELOAD_POLLING_MODE
endif

ifdef FF_USE_THREAD_STRUCT_HANDLE
CFLAGS+= -DFF_USE_THREAD_STRUCT_HANDLE
endif

CFLAGS += -fPIC -Wall -Werror $(shell $(PKGCONF) --cflags libdpdk)

INCLUDES= -I. -I${FF_PATH}/lib
Expand Down
2 changes: 2 additions & 0 deletions adapter/syscall/ff_adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
int ff_adapter_init();
//int __attribute__((constructor)) ff_adapter_init(int argc, char * const argv[]);

int ff_adapter_child_process_init(void);

void alarm_event_sem();

/*-
Expand Down
75 changes: 73 additions & 2 deletions adapter/syscall/ff_hook_syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -2137,13 +2137,39 @@ ff_hook_fork(void)
#ifdef FF_MULTI_SC
current_worker_id++;
ERR_LOG("parent process, current_worker_id++:%d\n", current_worker_id);
#endif
#ifdef FF_USE_THREAD_STRUCT_HANDLE
sc->forking = 1;
/* Loop until child fork done. */
while (sc->forking);
#endif
}
else if (pid == 0) {
ERR_LOG("chilid process, sc:%p, sc->refcount:%d, ff_so_zone:%p\n",
sc, sc->refcount, ff_so_zone);
#ifdef FF_MULTI_SC
ERR_LOG("chilid process, current_worker_id:%d\n", current_worker_id);
#endif
#ifdef FF_USE_THREAD_STRUCT_HANDLE
struct ff_so_context *parent_sc = sc;

/* Child process attach new sc */
ff_adapter_child_process_init();

/*
* The fork system call duplicates the file
* descriptors that were open in the parent process
*/
DEFINE_REQ_ARGS(fork);
args->parent_thread_handle = parent_sc->ff_thread_handle;
/* Output value */
args->child_thread_handle = NULL;
SYSCALL(FF_SO_FORK, args);
if (ret == 0) {
sc->ff_thread_handle = args->child_thread_handle;
}

parent_sc->forking = 0;
#endif
}

Expand Down Expand Up @@ -2442,6 +2468,16 @@ thread_destructor(void *sc)
}
}

static inline int
ff_application_exit(struct ff_so_context *sc)
{
DEFINE_REQ_ARGS(exit_application);
args->sc = sc;
SYSCALL(FF_SO_EXIT_APPLICATION, args);

return ret;
}

void __attribute__((destructor))
ff_adapter_exit()
{
Expand All @@ -2455,13 +2491,19 @@ ff_adapter_exit()
for (i = 0; i < worker_id; i++) {
ERR_LOG("pthread self tid:%lu, detach sc:%p\n", pthread_self(), scs[i].sc);
ff_so_zone = ff_so_zones[i];
ff_detach_so_context(scs[i].sc);
#ifdef FF_USE_THREAD_STRUCT_HANDLE
ff_application_exit(scs[i].sc);
#endif
ff_detach_so_context(scs[i].sc);
}
} else
#endif
{
ERR_LOG("pthread self tid:%lu, detach sc:%p\n", pthread_self(), sc);
ff_detach_so_context(sc);
#ifdef FF_USE_THREAD_STRUCT_HANDLE
ff_application_exit(sc);
#endif
ff_detach_so_context(sc);
sc = NULL;
}
#endif
Expand Down Expand Up @@ -2618,11 +2660,40 @@ ff_adapter_init()

rte_spinlock_unlock(&worker_id_lock);

#ifdef FF_USE_THREAD_STRUCT_HANDLE
/*
* Request to fstack, alloc sc->ff_thread_handle
* Every appliaction
*/
{
DEFINE_REQ_ARGS(register_application);
args->sc = sc;
SYSCALL(FF_SO_REGISTER_APPLICATION, args);
if (ret < 0) {
return -1;
}
}
#endif

ERR_LOG("ff_adapter_init success, sc:%p, status:%d, ops:%d\n", sc, sc->status, sc->ops);

return 0;
}

int
ff_adapter_child_process_init(void)
{
sc = ff_attach_so_context(0);
if (sc == NULL) {
ERR_LOG("ff_attach_so_context failed\n");
return -1;
}

ERR_LOG("ff_adapter_child_process_init success, sc:%p, status:%d, ops:%d\n", sc, sc->status, sc->ops);

return 0;
}

void
alarm_event_sem()
{
Expand Down
1 change: 1 addition & 0 deletions adapter/syscall/ff_so_zone.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ ff_create_so_memzone()
sc->status = FF_SC_IDLE;
sc->idx = i;
sc->refcount = 0;
sc->ff_thread_handle = NULL;
//so_zone_tmp->inuse[i] = 0;

if (sem_init(&sc->wait_sem, 1, 0) == -1) {
Expand Down
56 changes: 54 additions & 2 deletions adapter/syscall/ff_socket_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,41 @@ ff_sys_kevent(struct ff_kevent_args *args)
static pid_t
ff_sys_fork(struct ff_fork_args *args)
{
errno = ENOSYS;
return -1;
void *parent = args->parent_thread_handle;
/*
* Linux has performed a real fork, and at this point,
* we simply need to create a new thread and duplicate the file descriptors
* that the parent process has already opened.
*/
if (parent) {
args->child_thread_handle = ff_adapt_user_thread_add(parent);
}

return 0;
}

static int
ff_sys_register_thread(struct ff_register_application_args *args)
{
/* New user application, use default thread0 */
args->sc->ff_thread_handle = ff_adapt_user_thread_add(NULL);

if (args->sc->ff_thread_handle == NULL) {
return -1;
}

return 0;
}

static int
ff_sys_exit_thread(struct ff_exit_application_args *args)
{
/* Exit user application */
if (args->sc->ff_thread_handle) {
ff_adapt_user_thread_exit(args->sc->ff_thread_handle);
}

return 0;
}

static int
Expand Down Expand Up @@ -439,6 +472,10 @@ ff_so_handler(int ops, void *args)
return ff_sys_kevent((struct ff_kevent_args *)args);
case FF_SO_FORK:
return ff_sys_fork((struct ff_fork_args *)args);
case FF_SO_REGISTER_APPLICATION:
return ff_sys_register_thread((struct ff_register_application_args *)args);
case FF_SO_EXIT_APPLICATION:
return ff_sys_exit_thread((struct ff_exit_application_args *)args);
default:
break;
}
Expand All @@ -451,6 +488,11 @@ ff_so_handler(int ops, void *args)
static inline void
ff_handle_socket_ops(struct ff_so_context *sc)
{
#ifdef FF_USE_THREAD_STRUCT_HANDLE
void *old_thread;
void *ff_thread_handle = sc->ff_thread_handle;
#endif

if (!rte_spinlock_trylock(&sc->lock)) {
return;
}
Expand All @@ -463,7 +505,17 @@ ff_handle_socket_ops(struct ff_so_context *sc)
DEBUG_LOG("ff_handle_socket_ops sc:%p, status:%d, ops:%d\n", sc, sc->status, sc->ops);

errno = 0;
#ifdef FF_USE_THREAD_STRUCT_HANDLE
if (ff_thread_handle) {
old_thread = ff_switch_curthread(ff_thread_handle);
}
#endif
sc->result = ff_so_handler(sc->ops, sc->args);
#ifdef FF_USE_THREAD_STRUCT_HANDLE
if (ff_thread_handle) {
ff_restore_curthread(old_thread);
}
#endif
sc->error = errno;
DEBUG_LOG("ff_handle_socket_ops error:%d, ops:%d, result:%d\n", errno, sc->ops, sc->result);

Expand Down
4 changes: 4 additions & 0 deletions adapter/syscall/ff_socket_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ enum FF_SOCKET_OPS {
FF_SO_KQUEUE,
FF_SO_KEVENT,
FF_SO_FORK, // 29
FF_SO_REGISTER_APPLICATION,
FF_SO_EXIT_APPLICATION,
};

enum FF_SO_CONTEXT_STATUS {
Expand Down Expand Up @@ -110,6 +112,8 @@ struct ff_so_context {
/* CACHE LINE 1 */
/* listen fd, refcount.. */
int refcount;
void *ff_thread_handle;
volatile int forking;
} __attribute__((aligned(RTE_CACHE_LINE_SIZE)));

extern __FF_THREAD struct ff_socket_ops_zone *ff_so_zone;
Expand Down
9 changes: 9 additions & 0 deletions adapter/syscall/ff_sysproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,16 @@ struct ff_kevent_args {
};

struct ff_fork_args {
void *parent_thread_handle;
void *child_thread_handle;
};

struct ff_register_application_args {
struct ff_so_context *sc;
};

struct ff_exit_application_args {
struct ff_so_context *sc;
};

#endif
76 changes: 76 additions & 0 deletions freebsd/kern/kern_descrip.c
Original file line number Diff line number Diff line change
Expand Up @@ -2516,6 +2516,82 @@ fdclearlocks(struct thread *td)
free(fdtol, M_FILEDESC_TO_LEADER);
}

/*
* Release a filedesc structure, we use this.
*/
static void
fdescfree_fds_adapt_use(struct thread *td, struct filedesc *fdp, bool needclose)
{
struct filedesc0 *fdp0;
struct freetable *ft, *tft;
struct filedescent *fde;
struct file *fp;
int i, lastfile;

KASSERT(refcount_load(&fdp->fd_refcnt) == 0,
("%s: fd table %p carries references", __func__, fdp));

/*
* Serialize with threads iterating over the table, if any.
*/
if (refcount_load(&fdp->fd_holdcnt) > 1) {
FILEDESC_XLOCK(fdp);
FILEDESC_XUNLOCK(fdp);
}

lastfile = fdlastfile_single(fdp);
for (i = 0; i <= lastfile; i++) {
fde = &fdp->fd_ofiles[i];
fp = fde->fde_file;
if (fp != NULL) {
fdefree_last(fde);
if (needclose)
(void) closefp_impl(fdp, i, fp, td, true);
else
fdrop(fp, td);
}
}

if (NDSLOTS(fdp->fd_nfiles) > NDSLOTS(NDFILE))
free(fdp->fd_map, M_FILEDESC);
if (fdp->fd_nfiles > NDFILE)
free(fdp->fd_files, M_FILEDESC);

fdp0 = (struct filedesc0 *)fdp;
SLIST_FOREACH_SAFE(ft, &fdp0->fd_free, ft_next, tft)
free(ft->ft_table, M_FILEDESC);

fddrop(fdp);
}

void
fdescfree_adapt_use(struct thread *td)
{
struct proc *p;
struct filedesc *fdp;

p = td->td_proc;
fdp = p->p_fd;
MPASS(fdp != NULL);

#ifdef RACCT
if (RACCT_ENABLED())
racct_set_unlocked(p, RACCT_NOFILE, 0);
#endif

if (p->p_fdtol != NULL)
fdclearlocks(td);

if (refcount_release(&fdp->fd_refcnt) == 0)
return;

fdescfree_fds_adapt_use(td, fdp, 1);

PROC_LOCK(p);
p->p_fd = NULL;
PROC_UNLOCK(p);
}

/*
* Release a filedesc structure.
*/
Expand Down
1 change: 1 addition & 0 deletions freebsd/sys/filedesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ int fdcopy_remapped(struct filedesc *fdp, const int *fds, size_t nfds,
void fdinstall_remapped(struct thread *td, struct filedesc *fdp);
void fdunshare(struct thread *td);
void fdescfree(struct thread *td);
void fdescfree_adapt_use(struct thread *td);
void fdescfree_remapped(struct filedesc *fdp);
int fdlastfile(struct filedesc *fdp);
int fdlastfile_single(struct filedesc *fdp);
Expand Down
12 changes: 12 additions & 0 deletions lib/ff_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,18 @@ int ff_zc_mbuf_write(struct ff_zc_mbuf *m, const char *data, int len);
*/
int ff_zc_mbuf_read(struct ff_zc_mbuf *m, const char *data, int len);

/*
* Create user thread context for LD_PRELOAD mode.
* It saved in ff_so_context.
*/
void *ff_adapt_user_thread_add(void *parent);

void ff_adapt_user_thread_exit(void *td);

void *ff_switch_curthread(void *new_curthread);

void ff_restore_curthread(void *old_curthread);

/* ZERO COPY API end */

#ifdef __cplusplus
Expand Down
4 changes: 4 additions & 0 deletions lib/ff_api.symlist
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,7 @@ ff_pthread_join
pcurthread
ff_dpdk_raw_packet_send
ff_swi_net_excute
ff_adapt_user_thread_add
ff_adapt_user_thread_exit
ff_switch_curthread
ff_restore_curthread
Loading