freebsd_network: Rewrite ConditionVariable-using code.
The old code was not at all correct with respect to interlocking. The new code should be, and is also much simpler.
This commit is contained in:
parent
1960df3158
commit
33c03035d1
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 Colin Günther, coling@gmx.de
|
||||
* All Rights Reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
extern "C" {
|
||||
#include <compat/sys/condvar.h>
|
||||
#include <compat/sys/kernel.h>
|
||||
}
|
||||
|
||||
#include "Condvar.h"
|
||||
|
||||
|
||||
void
|
||||
conditionInit(struct cv* variable, const char* description)
|
||||
{
|
||||
variable->condition.Init(variable, description);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
conditionPublish(struct cv* variable, const void* waitChannel,
|
||||
const char* description)
|
||||
{
|
||||
variable->condition.Publish(waitChannel, description);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
conditionUnpublish(struct cv* variable)
|
||||
{
|
||||
variable->condition.Unpublish();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
conditionTimedWait(struct cv* variable, const int timeout)
|
||||
{
|
||||
status_t status = variable->condition.Wait(B_RELATIVE_TIMEOUT,
|
||||
TICKS_2_USEC(timeout));
|
||||
|
||||
if (status != B_OK)
|
||||
status = EWOULDBLOCK;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
conditionWait(struct cv* variable)
|
||||
{
|
||||
variable->condition.Wait();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
conditionNotifyOne(struct cv* variable)
|
||||
{
|
||||
variable->condition.NotifyOne();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
publishedConditionTimedWait(const void* waitChannel, const int timeout)
|
||||
{
|
||||
ConditionVariableEntry variableEntry;
|
||||
bigtime_t usecs = TICKS_2_USEC(timeout);
|
||||
|
||||
// FreeBSD has a condition-variable scheduling system with different
|
||||
// scheduling semantics than ours does. As a result, it seems there are
|
||||
// some scenarios which work fine under FreeBSD but race into a deadlock
|
||||
// on Haiku. To avoid this, turn unlimited timeouts into 1sec ones.
|
||||
status_t status = variableEntry.Wait(waitChannel, B_RELATIVE_TIMEOUT,
|
||||
usecs > 0 ? usecs : 1000 * 1000);
|
||||
|
||||
if (status != B_OK)
|
||||
status = EWOULDBLOCK;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
publishedConditionNotifyAll(const void* waitChannel)
|
||||
{
|
||||
ConditionVariable::NotifyAll(waitChannel, B_OK);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
publishedConditionNotifyOne(const void* waitChannel)
|
||||
{
|
||||
ConditionVariable::NotifyOne(waitChannel, B_OK);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 Colin Günther, coling@gmx.de
|
||||
* All Rights Reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CONDVAR_H_
|
||||
#define CONDVAR_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void conditionInit(struct cv*, const char*);
|
||||
void conditionPublish(struct cv*, const void*, const char*);
|
||||
void conditionUnpublish(struct cv*);
|
||||
int conditionTimedWait(struct cv*, const int);
|
||||
void conditionWait(struct cv*);
|
||||
void conditionNotifyOne(struct cv*);
|
||||
int publishedConditionTimedWait(const void*, const int);
|
||||
void publishedConditionNotifyAll(const void*);
|
||||
void publishedConditionNotifyOne(const void*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONDVAR_H_ */
|
@ -18,8 +18,7 @@ KernelStaticLibrary libfreebsd_network.a :
|
||||
bus_dma.cpp
|
||||
callout.cpp
|
||||
clock.c
|
||||
condvar.c
|
||||
Condvar.cpp
|
||||
condvar.cpp
|
||||
device.c
|
||||
device_hooks.c
|
||||
driver.c
|
||||
@ -45,7 +44,7 @@ KernelStaticLibrary libfreebsd_network.a :
|
||||
priv.cpp
|
||||
smp.c
|
||||
subr_autoconf.cpp
|
||||
synch.c
|
||||
synch.cpp
|
||||
systm.cpp
|
||||
sysinit.c
|
||||
taskqueue.c
|
||||
|
@ -99,8 +99,6 @@ extern int vsnprintf(char *, size_t, const char *, __va_list)
|
||||
int msleep(void *, struct mtx *, int, const char *, int);
|
||||
int _pause(const char *, int);
|
||||
#define pause(waitMessage, timeout) _pause((waitMessage), (timeout))
|
||||
#define tsleep(channel, priority, waitMessage, timeout) \
|
||||
msleep((channel), NULL, (priority), (waitMessage), (timeout))
|
||||
#define msleep_spin(chan, mtx, wmesg, timo) \
|
||||
msleep(chan, mtx, PZERO, wmesg, timo)
|
||||
#define mtx_sleep msleep
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 Colin Günther, coling@gmx.de.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <compat/sys/mutex.h>
|
||||
#include <compat/sys/condvar.h>
|
||||
|
||||
#include "Condvar.h"
|
||||
|
||||
|
||||
void cv_init(struct cv* variable, const char* description)
|
||||
{
|
||||
conditionInit(variable, description);
|
||||
}
|
||||
|
||||
|
||||
void cv_signal(struct cv* variable)
|
||||
{
|
||||
conditionNotifyOne(variable);
|
||||
}
|
||||
|
||||
|
||||
int cv_timedwait(struct cv* variable, struct mtx* mutex, int timeout)
|
||||
{
|
||||
int status;
|
||||
|
||||
mtx_unlock(mutex);
|
||||
status = conditionTimedWait(variable, timeout);
|
||||
mtx_lock(mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void cv_wait(struct cv* variable, struct mtx* mutex)
|
||||
{
|
||||
mtx_unlock(mutex);
|
||||
conditionWait(variable);
|
||||
mtx_lock(mutex);
|
||||
}
|
56
src/libs/compat/freebsd_network/condvar.cpp
Normal file
56
src/libs/compat/freebsd_network/condvar.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2022, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#include <compat/sys/mutex.h>
|
||||
#include <compat/sys/condvar.h>
|
||||
#include <compat/sys/kernel.h>
|
||||
|
||||
|
||||
void
|
||||
cv_init(struct cv* variable, const char* description)
|
||||
{
|
||||
variable->condition.Init(NULL, description);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cv_signal(struct cv* variable)
|
||||
{
|
||||
variable->condition.NotifyOne();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cv_timedwait(struct cv* variable, struct mtx* mutex, int timeout)
|
||||
{
|
||||
int status;
|
||||
|
||||
const uint32 flags = timeout ? B_RELATIVE_TIMEOUT : 0;
|
||||
const bigtime_t bigtimeout = TICKS_2_USEC(timeout);
|
||||
|
||||
if (mutex->type == MTX_RECURSE) {
|
||||
// Special case: let the ConditionVariable handle switching recursive locks.
|
||||
status = variable->condition.Wait(&mutex->u.recursive,
|
||||
flags, bigtimeout);
|
||||
return status;
|
||||
}
|
||||
|
||||
ConditionVariableEntry entry;
|
||||
variable->condition.Add(&entry);
|
||||
|
||||
mtx_unlock(mutex);
|
||||
|
||||
status = entry.Wait(flags, bigtimeout);
|
||||
|
||||
mtx_lock(mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cv_wait(struct cv* variable, struct mtx* mutex)
|
||||
{
|
||||
cv_timedwait(variable, mutex, 0);
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 Colin Günther, coling@gmx.de
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <compat/sys/systm.h>
|
||||
#include <compat/sys/kernel.h>
|
||||
#include <compat/sys/mutex.h>
|
||||
#include <compat/sys/condvar.h>
|
||||
|
||||
#include "Condvar.h"
|
||||
|
||||
|
||||
int
|
||||
msleep(void* identifier, struct mtx* mutex, int priority,
|
||||
const char* description, int timeout)
|
||||
{
|
||||
int status;
|
||||
struct cv sleep;
|
||||
|
||||
conditionPublish(&sleep, identifier, description);
|
||||
|
||||
// FreeBSD's msleep() does not allow the mutex to be NULL, but we
|
||||
// do, as we implement some other functions like tsleep() with it.
|
||||
if (mutex != NULL)
|
||||
mtx_unlock(mutex);
|
||||
|
||||
status = publishedConditionTimedWait(identifier, timeout);
|
||||
|
||||
if (mutex != NULL)
|
||||
mtx_lock(mutex);
|
||||
|
||||
conditionUnpublish(&sleep);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
wakeup(void* identifier)
|
||||
{
|
||||
publishedConditionNotifyAll(identifier);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
wakeup_one(void* identifier)
|
||||
{
|
||||
publishedConditionNotifyOne(identifier);
|
||||
}
|
37
src/libs/compat/freebsd_network/synch.cpp
Normal file
37
src/libs/compat/freebsd_network/synch.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2022, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#include <compat/sys/systm.h>
|
||||
#include <compat/sys/kernel.h>
|
||||
#include <compat/sys/mutex.h>
|
||||
#include <compat/sys/condvar.h>
|
||||
|
||||
|
||||
int
|
||||
msleep(void* identifier, struct mtx* mutex, int priority,
|
||||
const char* description, int timeout)
|
||||
{
|
||||
struct cv channel;
|
||||
channel.condition.Publish(identifier, description);
|
||||
|
||||
int status = cv_timedwait(&channel, mutex, timeout);
|
||||
|
||||
channel.condition.Unpublish();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
wakeup(void* identifier)
|
||||
{
|
||||
ConditionVariable::NotifyAll(identifier, B_OK);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
wakeup_one(void* identifier)
|
||||
{
|
||||
ConditionVariable::NotifyOne(identifier, B_OK);
|
||||
}
|
Loading…
Reference in New Issue
Block a user