Skip to content

Commit

Permalink
Merge pull request torvalds#130 from pscollins/free-all-mem
Browse files Browse the repository at this point in the history
Free all memory allocated by LKL (except for undetached pthreads)
  • Loading branch information
Octavian Purdila committed Mar 22, 2016
2 parents c4e50c2 + 61475a3 commit 21089ed
Show file tree
Hide file tree
Showing 12 changed files with 299 additions and 43 deletions.
10 changes: 7 additions & 3 deletions arch/lkl/include/uapi/asm/host_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ typedef unsigned long lkl_thread_t;
* @thread_detach - on POSIX systems, free up resources held by
* pthreads. Noop on Win32.
* @thread_exit - terminates the current thread
* @thread_join - wait for the given thread to terminate. Returns 0
* for success, -1 otherwise
*
* @tls_alloc - allocate a thread local storage key; returns 0 if succesful
* @tls_free - frees a thread local storage key; returns 0 if succesful
Expand All @@ -58,7 +60,8 @@ typedef unsigned long lkl_thread_t;
* @iomem_acess - reads or writes to and I/O memory region; addr must be in the
* range returned by ioremap
*
* @gettid - returns the host thread id of the caller
* @gettid - returns the host thread id of the caller, which need not
* be the same as the handle returned by thread_create
*/
struct lkl_host_operations {
const char *virtio_devices;
Expand All @@ -80,6 +83,7 @@ struct lkl_host_operations {
lkl_thread_t (*thread_create)(void (*f)(void *), void *arg);
void (*thread_detach)(void);
void (*thread_exit)(void);
int (*thread_join)(lkl_thread_t tid);

int (*tls_alloc)(unsigned int *key);
int (*tls_free)(unsigned int key);
Expand Down Expand Up @@ -113,7 +117,7 @@ struct lkl_host_operations {
* generate the Linux kernel command line
*/
int lkl_start_kernel(struct lkl_host_operations *lkl_ops,
unsigned long mem_size,
const char *cmd_line, ...);
unsigned long mem_size,
const char *cmd_line, ...);

#endif
14 changes: 8 additions & 6 deletions arch/lkl/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ static void __init lkl_run_kernel(void *arg)
}

int __init lkl_start_kernel(struct lkl_host_operations *ops,
unsigned long _mem_size,
const char *fmt, ...)
unsigned long _mem_size,
const char *fmt, ...)
{
va_list ap;
int ret;
Expand Down Expand Up @@ -117,6 +117,8 @@ void machine_restart(char *unused)
machine_halt();
}

extern int lkl_netdevs_remove(void);

long lkl_sys_halt(void)
{
long err;
Expand All @@ -139,6 +141,10 @@ long lkl_sys_halt(void)
lkl_ops->sem_free(init_sem);

free_initial_syscall_thread();
if (lkl_netdevs_remove() == 0)
/* We know that there is nothing else touching our
* memory. */
free_mem();

return 0;
}
Expand All @@ -147,10 +153,6 @@ void arch_cpu_idle(void)
{
if (halt) {
threads_cleanup();
/* TODO(pscollins): If we free here, it causes a
* segfault because the tx/rx threads are still
* running in parallel. */
/* free_mem(); */

/* Shutdown the clockevents source. */
tick_suspend_local();
Expand Down
18 changes: 13 additions & 5 deletions tools/lkl/include/lkl.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,9 @@ int lkl_if_set_ipv4(int ifindex, unsigned int addr, unsigned int netmask_len);
int lkl_set_ipv4_gateway(unsigned int addr);

/**
* lkl_netdev - host network device handle
* lkl_netdev - host network device handle, defined in lkl_host.h.
*/
struct lkl_netdev {
struct lkl_dev_net_ops *ops;
};

struct lkl_netdev;

/**
* lkl_netdev_add - add a new network device
Expand All @@ -228,6 +225,17 @@ struct lkl_netdev {
*/
int lkl_netdev_add(struct lkl_netdev *nd, void *mac);

/**
* lkl_netdevs_remove - destroy all network devices
*
* Attempts to release all resources held by network devices created
* via lkl_netdev_add.
*
* @returns 0 if all devices are successfully removed, -1 if at least
* one fails.
*/
int lkl_netdevs_remove(void);

/**
* lkl_netdev_get_ifindex - retrieve the interface index for a given network
* device id
Expand Down
9 changes: 9 additions & 0 deletions tools/lkl/include/lkl_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,21 @@ struct lkl_dev_blk_ops {
int (*request)(union lkl_disk disk, struct lkl_blk_req *req);
};

struct lkl_netdev {
struct lkl_dev_net_ops *ops;
lkl_thread_t rx_tid, tx_tid;
};

struct lkl_dev_net_ops {
int (*tx)(struct lkl_netdev *nd, void *data, int len);
int (*rx)(struct lkl_netdev *nd, void *data, int *len);
#define LKL_DEV_NET_POLL_RX 1
#define LKL_DEV_NET_POLL_TX 2
int (*poll)(struct lkl_netdev *nd, int events);
/* Release all resources acquired --- in particular, kill the
* polling threads and close any open handles. Not implemented
* by all netdev types. 0 for success, -1 for failure. */
int (*close)(struct lkl_netdev *nd);
};

#ifdef __cplusplus
Expand Down
16 changes: 14 additions & 2 deletions tools/lkl/lib/hijack/init.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


/*
* system calls hijack code
* Copyright (c) 2015 Hajime Tazaki
Expand Down Expand Up @@ -27,6 +25,10 @@
#include <lkl_host.h>

#include "xlate.h"
#include "../virtio_net_tap.h"

#define __USE_GNU
#include <dlfcn.h>

/* Mount points are named after filesystem types so they should never
* be longer than ~6 characters. */
Expand Down Expand Up @@ -139,6 +141,13 @@ static void mount_cmds_exec(char *_cmds, int (*callback)(char*))
free(cmds);
}

void fixup_netdev_tap_ops(void)
{
/* It's okay if this is NULL, because then netdev close will
* fall back onto an uncloseable implementation. */
lkl_netdev_tap_ops.eventfd = dlsym(RTLD_NEXT, "eventfd");
}

void __attribute__((constructor(102)))
hijack_init(void)
{
Expand All @@ -157,6 +166,9 @@ hijack_init(void)
char *mount = getenv("LKL_HIJACK_MOUNT");
struct lkl_netdev *nd = NULL;

/* Must be run before lkl_netdev_tap_create */
fixup_netdev_tap_ops();

if (tap) {
fprintf(stderr,
"WARN: variable LKL_HIJACK_NET_TAP is now obsoleted.\n"
Expand Down
17 changes: 16 additions & 1 deletion tools/lkl/lib/nt-host.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ static lkl_thread_t thread_create(void (*fn)(void *), void *arg)
{
DWORD WINAPI (*win_fn)(LPVOID arg) = (DWORD WINAPI (*)(LPVOID))fn;

return CreateThread(NULL, 0, win_fn, arg, 0, NULL);
return (lkl_thread_t)CreateThread(NULL, 0, win_fn, arg, 0, NULL);
}

static void thread_detach(void)
Expand All @@ -79,6 +79,13 @@ static void thread_exit(void)
ExitThread(0);
}

static int thread_join(lkl_thread_t tid)
{
/* TODO: error handling */
WaitForSingleObject(tid, INFINITE);
return 0;
}

static int tls_alloc(unsigned int *key)
{
*key = TlsAlloc();
Expand Down Expand Up @@ -202,6 +209,7 @@ struct lkl_host_operations lkl_host_ops = {
.thread_create = thread_create,
.thread_detach = thread_detach,
.thread_exit = thread_exit,
.thread_join = thread_join,
.sem_alloc = sem_alloc,
.sem_free = sem_free,
.sem_up = sem_up,
Expand Down Expand Up @@ -301,3 +309,10 @@ struct lkl_dev_blk_ops lkl_dev_blk_ops = {
.get_capacity = handle_get_capacity,
.request = blk_request,
};

/* Needed to resolve linker error on Win32. We don't really support
* any network IO on Windows, anyway, so there's no loss here. */
int lkl_netdevs_remove(void)
{
return -1;
}
10 changes: 9 additions & 1 deletion tools/lkl/lib/posix-host.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,14 @@ static void thread_exit(void)
pthread_exit(NULL);
}

static int thread_join(lkl_thread_t tid)
{
if (WARN_PTHREAD(pthread_join(tid, NULL)))
return -1;
else
return 0;
}

static int tls_alloc(unsigned int *key)
{
return pthread_key_create((pthread_key_t*)key, NULL);
Expand All @@ -219,7 +227,6 @@ static void *tls_get(unsigned int key)
return pthread_getspecific(key);
}


static unsigned long long time_ns(void)
{
struct timeval tv;
Expand Down Expand Up @@ -286,6 +293,7 @@ struct lkl_host_operations lkl_host_ops = {
.thread_create = thread_create,
.thread_detach = thread_detach,
.thread_exit = thread_exit,
.thread_join = thread_join,
.sem_alloc = sem_alloc,
.sem_free = sem_free,
.sem_up = sem_up,
Expand Down
71 changes: 65 additions & 6 deletions tools/lkl/lib/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#define NUM_QUEUES (TX_QUEUE_IDX + 1)
#define QUEUE_DEPTH 32

/* In fact, we'll hit the limit on the devs string below long before
* we hit this, but it's good enough for now. */
#define MAX_NET_DEVS 16

#ifdef DEBUG
#define bad_request(s) do { \
lkl_printf("%s\n", s); \
Expand All @@ -23,7 +27,6 @@
#define bad_request(s) lkl_printf("virtio_net: %s\n", s);
#endif /* DEBUG */


struct virtio_net_poll {
struct virtio_net_dev *dev;
int event;
Expand Down Expand Up @@ -124,6 +127,22 @@ void poll_thread(void *arg)
}
}

struct virtio_net_dev *registered_devs[MAX_NET_DEVS];
static int registered_dev_idx = 0;

static int dev_register(struct virtio_net_dev *dev)
{
if (registered_dev_idx == MAX_NET_DEVS) {
lkl_printf("Too many virtio_net devices!\n");
/* This error code is a little bit of a lie */
return -LKL_ENOMEM;
} else {
/* registered_dev_idx is incremented by the caller */
registered_devs[registered_dev_idx] = dev;
return 0;
}
}

static void free_queue_locks(struct lkl_mutex_t **queues, int num_queues)
{
int i = 0;
Expand Down Expand Up @@ -158,7 +177,6 @@ static struct lkl_mutex_t **init_queue_locks(int num_queues)
int lkl_netdev_add(struct lkl_netdev *nd, void *mac)
{
struct virtio_net_dev *dev;
static int count;
int ret = -LKL_ENOMEM;

dev = lkl_host_ops.mem_alloc(sizeof(*dev));
Expand Down Expand Up @@ -198,15 +216,19 @@ int lkl_netdev_add(struct lkl_netdev *nd, void *mac)
if (ret)
goto out_free;

if (lkl_host_ops.thread_create(poll_thread, &dev->rx_poll) == 0)
nd->rx_tid = lkl_host_ops.thread_create(poll_thread, &dev->rx_poll);
if (nd->rx_tid == 0)
goto out_cleanup_dev;

if (lkl_host_ops.thread_create(poll_thread, &dev->tx_poll) == 0)
nd->tx_tid = lkl_host_ops.thread_create(poll_thread, &dev->tx_poll);
if (nd->tx_tid == 0)
goto out_cleanup_dev;

/* RX/TX thread polls will exit when the host netdev handle is closed */
ret = dev_register(dev);
if (ret < 0)
goto out_cleanup_dev;

return count++;
return registered_dev_idx++;

out_cleanup_dev:
virtio_dev_cleanup(&dev->dev);
Expand All @@ -218,3 +240,40 @@ int lkl_netdev_add(struct lkl_netdev *nd, void *mac)

return ret;
}

/* Return 0 for success, -1 for failure. */
static int lkl_netdev_remove(struct virtio_net_dev *dev)
{
if (!dev->nd->ops->close)
/* Can't kill the poll threads, so we can't do
* anything safely. */
return -1;

if (dev->nd->ops->close(dev->nd) < 0)
/* Something went wrong */
return -1;

virtio_dev_cleanup(&dev->dev);

lkl_host_ops.mem_free(dev->nd);
free_queue_locks(dev->queue_locks, NUM_QUEUES);
lkl_host_ops.mem_free(dev);

return 0;
}

int lkl_netdevs_remove(void)
{
int i = 0, failure_count = 0;

for (; i < registered_dev_idx; i++)
failure_count -= lkl_netdev_remove(registered_devs[i]);

if (failure_count) {
lkl_printf("WARN: failed to free %d of %d netdevs.\n",
failure_count, registered_dev_idx);
return -1;
}

return 0;
}
Loading

0 comments on commit 21089ed

Please sign in to comment.