From e7c3a8ffd7434cff9662772e1fd12d336b2073ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 19 Jul 2010 10:41:16 +0000 Subject: [PATCH] Fixed a few regressions that were introduced during the last months: * device_attach() must not load the network stack. Besides being completely unbalanced, this was also one reason why the stack could not be unloaded anymore. Instead, it's now done in compat_open(), as before. * This also fixes network booting from FreeBSD drivers - the stack apparently could not be initialized that early. * Replaced the previous network stack based callout implementation with one that mostly copies its functionality, but has no dependencies. Furthermore, it runs at a higher priority (the one of the network timer should also be revisited, though). * Fixed mtx_owned() to work without KDEBUG as well. It's not a good idea to introduce code that behaves completely different based on debug settings. * Minor cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37580 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/libs/compat/freebsd_network/Jamfile | 3 +- src/libs/compat/freebsd_network/callout.c | 80 ------ src/libs/compat/freebsd_network/callout.cpp | 237 ++++++++++++++++++ src/libs/compat/freebsd_network/compat.c | 9 +- .../freebsd_network/compat/sys/_mutex.h | 14 +- .../freebsd_network/compat/sys/callout.h | 15 +- .../compat/freebsd_network/compat/sys/mutex.h | 33 ++- src/libs/compat/freebsd_network/device.c | 3 + src/libs/compat/freebsd_network/device.h | 3 + src/libs/compat/freebsd_network/driver.c | 15 +- src/libs/compat/freebsd_network/mutex.c | 16 +- src/libs/compat/freebsd_network/timeout.c | 26 -- 12 files changed, 297 insertions(+), 157 deletions(-) delete mode 100644 src/libs/compat/freebsd_network/callout.c create mode 100644 src/libs/compat/freebsd_network/callout.cpp delete mode 100644 src/libs/compat/freebsd_network/timeout.c diff --git a/src/libs/compat/freebsd_network/Jamfile b/src/libs/compat/freebsd_network/Jamfile index d84533ebb3..1dddf1817e 100644 --- a/src/libs/compat/freebsd_network/Jamfile +++ b/src/libs/compat/freebsd_network/Jamfile @@ -14,7 +14,7 @@ SubDirCcFlags [ FDefines _KERNEL=1 ] ; KernelStaticLibrary libfreebsd_network.a : bus.c - callout.c + callout.cpp clock.c compat.c compat_cpp.cpp @@ -40,7 +40,6 @@ KernelStaticLibrary libfreebsd_network.a : priv.c synch.c taskqueue.c - timeout.c unit.c Unit.cpp ; diff --git a/src/libs/compat/freebsd_network/callout.c b/src/libs/compat/freebsd_network/callout.c deleted file mode 100644 index 007435e66b..0000000000 --- a/src/libs/compat/freebsd_network/callout.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2009, Colin Günther, coling@gmx.de. - * Copyright 2007, Hugo Santos. All Rights Reserved. - * Distributed under the terms of the MIT License. - */ - - -#include "device.h" - -#include - - -static void -handle_callout(struct net_timer *timer, void *data) -{ - struct callout *c = data; - struct mtx *c_mtx = c->c_mtx; - - if (c_mtx) - mtx_lock(c_mtx); - - /* FreeBSD 6.2 uses THREAD_NO_SLEEPING/THREAD_SLEEPING_OK when calling the - * callback */ - - c->c_func(c->c_arg); - - if (c_mtx) - mtx_unlock(c_mtx); -} - - -// #pragma mark - - - -void -callout_init_mtx(struct callout *c, struct mtx *mtx, int flags) -{ - gStack->init_timer(&c->c_timer, handle_callout, c); - - c->c_arg = NULL; - c->c_func = NULL; - c->c_mtx = mtx; - c->c_flags = flags; -} - - -int -callout_reset(struct callout *c, int when, void (*func)(void *), void *arg) -{ - int canceled = gStack->cancel_timer(&c->c_timer) ? 1 : 0; - - c->c_func = func; - c->c_arg = arg; - - gStack->set_timer(&c->c_timer, when); - - return canceled; -} - - -int -_callout_stop_safe(struct callout *c, int safe) -{ - return gStack->cancel_timer(&c->c_timer) ? 1 : 0; -} - - -int -callout_pending(struct callout *c) -{ - return gStack->is_timer_active(&c->c_timer); -} - - -int -callout_active(struct callout *c) -{ - return gStack->is_timer_running(&c->c_timer); -} - diff --git a/src/libs/compat/freebsd_network/callout.cpp b/src/libs/compat/freebsd_network/callout.cpp new file mode 100644 index 0000000000..f062da5824 --- /dev/null +++ b/src/libs/compat/freebsd_network/callout.cpp @@ -0,0 +1,237 @@ +/* + * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "device.h" + +#include +#include + +extern "C" { +# include +# include +} + +#include + + +//#define TRACE_CALLOUT +#ifdef TRACE_CALLOUT +# define TRACE(x...) dprintf(x) +#else +# define TRACE(x...) ; +#endif + + +static struct list sTimers; +static mutex sLock; +static sem_id sWaitSem; +static callout* sCurrentCallout; +static thread_id sThread; +static bigtime_t sTimeout; + + +static status_t +callout_thread(void* /*data*/) +{ + status_t status = B_OK; + + do { + bigtime_t timeout = B_INFINITE_TIMEOUT; + + if (status == B_TIMED_OUT || status == B_OK) { + // scan timers for new timeout and/or execute a timer + mutex_lock(&sLock); + + while (true) { + struct callout* c = (callout*)list_get_next_item(&sTimers, c); + if (c == NULL) + break; + + if (c->due < system_time()) { + struct mtx *mutex = c->c_mtx; + + // execute timer + list_remove_item(&sTimers, c); + c->due = -1; + sCurrentCallout = c; + + mutex_unlock(&sLock); + + if (mutex != NULL) + mtx_lock(mutex); + + c->c_func(c->c_arg); + + if (mutex != NULL) + mtx_unlock(mutex); + + mutex_lock(&sLock); + + sCurrentCallout = NULL; + c = NULL; + // restart scanning as we unlocked the list + } else { + // calculate new timeout + if (c->due < timeout) + timeout = c->due; + } + } + + sTimeout = timeout; + mutex_unlock(&sLock); + } + + status = acquire_sem_etc(sWaitSem, 1, B_ABSOLUTE_TIMEOUT, timeout); + // the wait sem normally can't be acquired, so we + // have to look at the status value the call returns: + // + // B_OK - a new timer has been added or canceled + // B_TIMED_OUT - look for timers to be executed + // B_BAD_SEM_ID - we are asked to quit + } while (status != B_BAD_SEM_ID); + + return B_OK; +} + + +// #pragma mark - private API + + +status_t +init_callout(void) +{ + list_init(&sTimers); + sTimeout = B_INFINITE_TIMEOUT; + + status_t status = B_OK; + mutex_init(&sLock, "fbsd callout"); + + sWaitSem = create_sem(0, "fbsd callout wait"); + if (sWaitSem < 0) { + status = sWaitSem; + goto err1; + } + + sThread = spawn_kernel_thread(callout_thread, "fbsd callout", + B_URGENT_DISPLAY_PRIORITY, NULL); + if (sThread < 0) { + status = sThread; + goto err2; + } + + return resume_thread(sThread); + +err1: + mutex_destroy(&sLock); +err2: + delete_sem(sWaitSem); + return status; +} + + +void +uninit_callout(void) +{ + delete_sem(sWaitSem); + mutex_lock(&sLock); + + mutex_destroy(&sLock); + + status_t status; + wait_for_thread(sThread, &status); +} + + +// #pragma mark - public API + + +void +callout_init(struct callout *callout, int mpsafe) +{ + if (mpsafe) + callout_init_mtx(callout, NULL, 0); + else + callout_init_mtx(callout, &Giant, 0); +} + + +void +callout_init_mtx(struct callout *c, struct mtx *mtx, int flags) +{ + c->due = 0; + c->flags = 0; + + c->c_arg = NULL; + c->c_func = NULL; + c->c_mtx = mtx; + c->c_flags = flags; +} + + +int +callout_reset(struct callout *c, int when, void (*func)(void *), void *arg) +{ + int canceled = callout_stop(c); + + MutexLocker locker(sLock); + + c->c_func = func; + c->c_arg = arg; + + TRACE("callout_reset %p, func %p, arg %p\n", c, c->c_func, c->c_arg); + + if (when >= 0) { + // reschedule or add this timer + if (c->due <= 0) + list_add_item(&sTimers, c); + + c->due = system_time() + when; + + // notify timer about the change if necessary + if (sTimeout > c->due) + release_sem(sWaitSem); + } + + return canceled; +} + + +int +callout_schedule(struct callout *callout, int toTicks) +{ + return callout_reset(callout, toTicks, callout->c_func, callout->c_arg); +} + + +int +_callout_stop_safe(struct callout *c, int safe) +{ + MutexLocker locker(sLock); + + TRACE("_callout_stop_safe %p, func %p, arg %p\n", c, c->c_func, c->c_arg); + + if (c->due <= 0) + return 0; + + // this timer is scheduled, cancel it + list_remove_item(&sTimers, c); + c->due = 0; + return 1; +} + + +int +callout_pending(struct callout *c) +{ + return c->due > 0; +} + + +int +callout_active(struct callout *c) +{ + return c == sCurrentCallout; +} diff --git a/src/libs/compat/freebsd_network/compat.c b/src/libs/compat/freebsd_network/compat.c index b5c6cc663f..da811cc354 100644 --- a/src/libs/compat/freebsd_network/compat.c +++ b/src/libs/compat/freebsd_network/compat.c @@ -385,18 +385,13 @@ device_attach(device_t device) || device->methods.attach == NULL) return B_ERROR; - if (get_module(NET_STACK_MODULE_NAME, (module_info **)&gStack) != B_OK) - return B_ERROR; - result = device->methods.attach(device); - if (result == 0) { + if (result == 0) atomic_or(&device->flags, DEVICE_ATTACHED); - } - if (result == 0) { + if (result == 0) result = start_wlan(device); - } return result; } diff --git a/src/libs/compat/freebsd_network/compat/sys/_mutex.h b/src/libs/compat/freebsd_network/compat/sys/_mutex.h index 8337989732..7d8e757c53 100644 --- a/src/libs/compat/freebsd_network/compat/sys/_mutex.h +++ b/src/libs/compat/freebsd_network/compat/sys/_mutex.h @@ -7,12 +7,18 @@ #define _FBSD_COMPAT_SYS__MUTEX_H_ +#include + + struct mtx { - int type; + int type; union { - mutex mutex; - int32 spinlock; - recursive_lock recursive; + struct { + mutex lock; + thread_id owner; + } mutex; + int32 spinlock; + recursive_lock recursive; } u; }; diff --git a/src/libs/compat/freebsd_network/compat/sys/callout.h b/src/libs/compat/freebsd_network/compat/sys/callout.h index c625569890..50909aa95f 100644 --- a/src/libs/compat/freebsd_network/compat/sys/callout.h +++ b/src/libs/compat/freebsd_network/compat/sys/callout.h @@ -1,4 +1,5 @@ /* + * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. * Copyright 2009, Colin Günther, coling@gmx.de. * Copyright 2007, Hugo Santos. All Rights Reserved. * Distributed under the terms of the MIT License. @@ -13,7 +14,10 @@ struct callout { - struct net_timer c_timer; + struct list_link link; + bigtime_t due; + uint32 flags; + void * c_arg; void (*c_func)(void *); struct mtx * c_mtx; @@ -24,18 +28,17 @@ struct callout { #define CALLOUT_MPSAFE 0x0001 +void callout_init(struct callout *c, int mpsafe); void callout_init_mtx(struct callout *c, struct mtx *mutex, int flags); -int callout_reset(struct callout *c, int, void (*func)(void *), void *arg); +int callout_schedule(struct callout *c, int when); +int callout_reset(struct callout *c, int when, void (*func)(void *), void *arg); int callout_pending(struct callout *c); int callout_active(struct callout *c); #define callout_drain(c) _callout_stop_safe(c, 1) #define callout_stop(c) _callout_stop_safe(c, 0) -int _callout_stop_safe(struct callout *, int); +int _callout_stop_safe(struct callout *c, int safe); -inline void -callout_init(struct callout *c, int mpsafe); -int callout_schedule(struct callout *, int); #endif /* _FBSD_COMPAT_SYS_CALLOUT_H_ */ diff --git a/src/libs/compat/freebsd_network/compat/sys/mutex.h b/src/libs/compat/freebsd_network/compat/sys/mutex.h index c17eec435f..6d0d31977a 100644 --- a/src/libs/compat/freebsd_network/compat/sys/mutex.h +++ b/src/libs/compat/freebsd_network/compat/sys/mutex.h @@ -42,9 +42,10 @@ void mtx_destroy(struct mtx*); static inline void mtx_lock(struct mtx* mutex) { - if (mutex->type == MTX_DEF) - mutex_lock(&mutex->u.mutex); - else if (mutex->type == MTX_RECURSE) + if (mutex->type == MTX_DEF) { + mutex_lock(&mutex->u.mutex.lock); + mutex->u.mutex.owner = thread_get_current_thread_id(); + } else if (mutex->type == MTX_RECURSE) recursive_lock_lock(&mutex->u.recursive); } @@ -52,9 +53,10 @@ mtx_lock(struct mtx* mutex) static inline void mtx_unlock(struct mtx* mutex) { - if (mutex->type == MTX_DEF) - mutex_unlock(&mutex->u.mutex); - else if (mutex->type == MTX_RECURSE) + if (mutex->type == MTX_DEF) { + mutex->u.mutex.owner = -1; + mutex_unlock(&mutex->u.mutex.lock); + } else if (mutex->type == MTX_RECURSE) recursive_lock_unlock(&mutex->u.recursive); } @@ -62,7 +64,7 @@ mtx_unlock(struct mtx* mutex) static inline int mtx_initialized(struct mtx* mutex) { - /* XXX */ + /* TODO */ return 1; } @@ -71,22 +73,17 @@ static inline int mtx_owned(struct mtx* mutex) { if (mutex->type == MTX_DEF) -#if KDEBUG - return mutex->u.mutex.holder == thread_get_current_thread_id(); -#else - return 0; - // found no way how to determine the holder of the mutex - // so we setting it to 0 because a starving thread is easier - // to detect than a race condition; Colin Günther -#endif - else if (mutex->type == MTX_RECURSE) + return mutex->u.mutex.owner == thread_get_current_thread_id(); + if (mutex->type == MTX_RECURSE) { #if KDEBUG return mutex->u.recursive.lock.holder == thread_get_current_thread_id(); #else return mutex->u.recursive.holder == thread_get_current_thread_id(); #endif - else - return 0; + } + + return 0; } + #endif /* _FBSD_COMPAT_SYS_MUTEX_H_ */ diff --git a/src/libs/compat/freebsd_network/device.c b/src/libs/compat/freebsd_network/device.c index 14bd1664a2..fc47ea4ef4 100644 --- a/src/libs/compat/freebsd_network/device.c +++ b/src/libs/compat/freebsd_network/device.c @@ -37,6 +37,9 @@ compat_open(const char *name, uint32 flags, void **cookie) if (i == MAX_DEVICES) return B_ERROR; + if (get_module(NET_STACK_MODULE_NAME, (module_info **)&gStack) != B_OK) + return B_ERROR; + ifp = gDevices[i]; if_printf(ifp, "compat_open(0x%lx)\n", flags); diff --git a/src/libs/compat/freebsd_network/device.h b/src/libs/compat/freebsd_network/device.h index 0a6349f809..481d4d4142 100644 --- a/src/libs/compat/freebsd_network/device.h +++ b/src/libs/compat/freebsd_network/device.h @@ -68,6 +68,9 @@ void uninit_taskqueues(void); status_t init_hard_clock(void); void uninit_hard_clock(void); +status_t init_callout(void); +void uninit_callout(void); + device_t find_root_device(int); /* busdma_machdep.c */ diff --git a/src/libs/compat/freebsd_network/driver.c b/src/libs/compat/freebsd_network/driver.c index 1679a44fc7..57d943e925 100644 --- a/src/libs/compat/freebsd_network/driver.c +++ b/src/libs/compat/freebsd_network/driver.c @@ -166,17 +166,21 @@ _fbsd_init_driver(driver_t *driver) if (status < B_OK) goto err3; + status = init_callout(); + if (status < B_OK) + goto err4; + init_bounce_pages(); if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) { status = init_taskqueues(); if (status < B_OK) - goto err4; + goto err5; } status = init_wlan_stack(); if (status < B_OK) - goto err5; + goto err6; while (gDeviceCount < MAX_DEVICES) { device_t root, device; @@ -214,11 +218,13 @@ _fbsd_init_driver(driver_t *driver) uninit_wlan_stack(); -err5: +err6: if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) uninit_taskqueues(); -err4: +err5: uninit_mbufs(); +err4: + uninit_callout(); err3: uninit_mutexes(); err2: @@ -248,6 +254,7 @@ _fbsd_uninit_driver(driver_t *driver) uninit_mbufs(); if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) uninit_taskqueues(); + uninit_callout(); uninit_mutexes(); put_module(B_PCI_MODULE_NAME); diff --git a/src/libs/compat/freebsd_network/mutex.c b/src/libs/compat/freebsd_network/mutex.c index 7c7ecbef0e..82333ac1f2 100644 --- a/src/libs/compat/freebsd_network/mutex.c +++ b/src/libs/compat/freebsd_network/mutex.c @@ -2,9 +2,6 @@ * Copyright 2009, Colin Günther, coling@gmx.de. * Copyright 2007, Hugo Santos. All Rights Reserved. * Distributed under the terms of the MIT License. - * - * Authors: - * Hugo Santos, hugosantos@gmail.com */ @@ -25,12 +22,13 @@ mtx_init(struct mtx *mutex, const char *name, const char *type, int options) { if (options == MTX_DEF) { - mutex_init_etc(&mutex->u.mutex, name, MUTEX_FLAG_CLONE_NAME); + mutex_init_etc(&mutex->u.mutex.lock, name, MUTEX_FLAG_CLONE_NAME); + mutex->u.mutex.owner = -1; } else if (options == MTX_RECURSE) { recursive_lock_init_etc(&mutex->u.recursive, name, MUTEX_FLAG_CLONE_NAME); } else - panic("Uh-oh, someone is pressing the wrong buttons"); + panic("fbsd: unsupported mutex type"); mutex->type = options; } @@ -39,12 +37,10 @@ mtx_init(struct mtx *mutex, const char *name, const char *type, void mtx_destroy(struct mtx *mutex) { - if (mutex->type == MTX_DEF) { - mutex_destroy(&mutex->u.mutex); - } else if (mutex->type == MTX_RECURSE) { + if (mutex->type == MTX_DEF) + mutex_destroy(&mutex->u.mutex.lock); + else if (mutex->type == MTX_RECURSE) recursive_lock_destroy(&mutex->u.recursive); - } else - panic("Uh-oh, someone is pressing the wrong buttons"); } diff --git a/src/libs/compat/freebsd_network/timeout.c b/src/libs/compat/freebsd_network/timeout.c deleted file mode 100644 index dd6817ea92..0000000000 --- a/src/libs/compat/freebsd_network/timeout.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2009, Colin Günther, coling@gmx.de - * Copyright 2007, Hugo Santos. All Rights Reserved. - * Distributed under the terms of the MIT License. - */ - - -#include -#include - - -inline void -callout_init(struct callout *callout, int mpsafe) -{ - if (mpsafe) - callout_init_mtx(callout, NULL, 0); - else - callout_init_mtx(callout, &Giant, 0); -} - - -int -callout_schedule(struct callout *callout, int to_ticks) -{ - return callout_reset(callout, to_ticks, callout->c_func, callout->c_arg); -}