* Added a net_timer::flags field, and used it to implement the new

wait_for_timer() function.
* Moved the internal Fifo class into utility.cpp - we should probably just
  remove it again.
* Fixed uninit_timers() so that it would even work in combination with the
  timer thread if there are timers left to be scheduled.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26980 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-08-15 14:46:16 +00:00
parent 2bf20e253b
commit 9e8be8bb9c
4 changed files with 149 additions and 105 deletions
+2
View File
@@ -44,6 +44,7 @@ struct net_timer {
net_timer_func hook; net_timer_func hook;
void *data; void *data;
bigtime_t due; bigtime_t due;
uint32 flags;
}; };
typedef int32 (*net_deframe_func)(struct net_device *device, typedef int32 (*net_deframe_func)(struct net_device *device,
@@ -140,6 +141,7 @@ struct net_stack_module_info {
void (*init_timer)(struct net_timer *timer, net_timer_func hook, void *data); void (*init_timer)(struct net_timer *timer, net_timer_func hook, void *data);
void (*set_timer)(struct net_timer *timer, bigtime_t delay); void (*set_timer)(struct net_timer *timer, bigtime_t delay);
bool (*cancel_timer)(struct net_timer *timer); bool (*cancel_timer)(struct net_timer *timer);
void (*wait_for_timer)(struct net_timer *timer);
bool (*is_timer_active)(struct net_timer *timer); bool (*is_timer_active)(struct net_timer *timer);
// syscall restart // syscall restart
@@ -913,6 +913,7 @@ net_stack_module_info gNetStackModule = {
init_timer, init_timer,
set_timer, set_timer,
cancel_timer, cancel_timer,
wait_for_timer,
is_timer_active, is_timer_active,
is_syscall, is_syscall,
+73 -9
View File
@@ -7,20 +7,57 @@
*/ */
#include "stack_private.h"
#include "utility.h" #include "utility.h"
#include <ByteOrder.h>
#include <KernelExport.h>
#include <condition_variable.h>
#include <net_buffer.h> #include <net_buffer.h>
#include <syscall_restart.h> #include <syscall_restart.h>
#include <util/AutoLock.h> #include <util/AutoLock.h>
#include <ByteOrder.h> #include "stack_private.h"
#include <KernelExport.h>
#define TIMER_IS_RUNNING 0x80000000
// internal Fifo class which doesn't maintain it's own lock
// TODO: do we need this one for anything?
class Fifo {
public:
Fifo(const char* name, size_t maxBytes);
~Fifo();
status_t InitCheck() const;
status_t Enqueue(net_buffer* buffer);
status_t EnqueueAndNotify(net_buffer* _buffer, net_socket* socket,
uint8 event);
status_t Wait(mutex* lock, bigtime_t timeout);
net_buffer* Dequeue(bool clone);
status_t Clear();
void WakeAll();
bool IsEmpty() const { return current_bytes == 0; }
//private:
// these field names are kept so we can use templatized
// functions together with net_fifo
sem_id notify;
int32 waiting;
size_t max_bytes;
size_t current_bytes;
struct list buffers;
};
static struct list sTimers; static struct list sTimers;
static mutex sTimerLock; static mutex sTimerLock;
static sem_id sTimerWaitSem; static sem_id sTimerWaitSem;
static ConditionVariable sWaitForTimerCondition;
static thread_id sTimerThread; static thread_id sTimerThread;
static bigtime_t sTimerTimeout; static bigtime_t sTimerTimeout;
@@ -51,7 +88,8 @@ base_fifo_init(FifoType *fifo, const char *name, size_t maxBytes)
template<typename FifoType> static inline status_t template<typename FifoType> static inline status_t
base_fifo_enqueue_buffer(FifoType* fifo, net_buffer* buffer) base_fifo_enqueue_buffer(FifoType* fifo, net_buffer* buffer)
{ {
if (fifo->max_bytes > 0 && fifo->current_bytes + buffer->size > fifo->max_bytes) if (fifo->max_bytes > 0
&& fifo->current_bytes + buffer->size > fifo->max_bytes)
return ENOBUFS; return ENOBUFS;
list_add_item(&fifo->buffers, buffer); list_add_item(&fifo->buffers, buffer);
@@ -286,8 +324,7 @@ fifo_enqueue_buffer(net_fifo *fifo, net_buffer *buffer)
} }
/*! /*! Gets the first buffer from the FIFO. If there is no buffer, it
Gets the first buffer from the FIFO. If there is no buffer, it
will wait depending on the \a flags and \a timeout. will wait depending on the \a flags and \a timeout.
The following flags are supported (the rest is ignored): The following flags are supported (the rest is ignored):
MSG_DONTWAIT - ignores the timeout and never wait for a buffer; if your MSG_DONTWAIT - ignores the timeout and never wait for a buffer; if your
@@ -392,8 +429,7 @@ timer_thread(void * /*data*/)
if (status == B_TIMED_OUT || status == B_OK) { if (status == B_TIMED_OUT || status == B_OK) {
// scan timers for new timeout and/or execute a timer // scan timers for new timeout and/or execute a timer
if (mutex_lock(&sTimerLock) < B_OK) mutex_lock(&sTimerLock);
return B_OK;
struct net_timer* timer = NULL; struct net_timer* timer = NULL;
while (true) { while (true) {
@@ -405,11 +441,14 @@ timer_thread(void * /*data*/)
// execute timer // execute timer
list_remove_item(&sTimers, timer); list_remove_item(&sTimers, timer);
timer->due = -1; timer->due = -1;
timer->flags |= TIMER_IS_RUNNING;
mutex_unlock(&sTimerLock); mutex_unlock(&sTimerLock);
timer->hook(timer, timer->data); timer->hook(timer, timer->data);
mutex_lock(&sTimerLock); mutex_lock(&sTimerLock);
timer->flags &= ~TIMER_IS_RUNNING;
sWaitForTimerCondition.NotifyAll();
timer = NULL; timer = NULL;
// restart scanning as we unlocked the list // restart scanning as we unlocked the list
} else { } else {
@@ -446,6 +485,7 @@ init_timer(net_timer *timer, net_timer_func hook, void *data)
timer->hook = hook; timer->hook = hook;
timer->data = data; timer->data = data;
timer->due = 0; timer->due = 0;
timer->flags = 0;
} }
@@ -497,6 +537,26 @@ cancel_timer(struct net_timer *timer)
} }
void
wait_for_timer(struct net_timer* timer)
{
while (true) {
MutexLocker locker(sTimerLock);
if (timer->due <= 0 && (timer->flags & TIMER_IS_RUNNING) == 0)
return;
// we actually need to wait for this timer
ConditionVariableEntry entry;
sWaitForTimerCondition.Add(&entry);
locker.Unlock();
entry.Wait();
}
}
bool bool
is_timer_active(net_timer* timer) is_timer_active(net_timer* timer)
{ {
@@ -545,6 +605,8 @@ init_timers(void)
goto err2; goto err2;
} }
sWaitForTimerCondition.Init(NULL, "wait for net timer");
add_debugger_command("net_timer", dump_timer, add_debugger_command("net_timer", dump_timer,
"Lists all active network timer"); "Lists all active network timer");
@@ -561,8 +623,10 @@ err2:
void void
uninit_timers(void) uninit_timers(void)
{ {
mutex_destroy(&sTimerLock);
delete_sem(sTimerWaitSem); delete_sem(sTimerWaitSem);
mutex_lock(&sTimerLock);
mutex_destroy(&sTimerLock);
status_t status; status_t status;
wait_for_thread(sTimerThread, &status); wait_for_thread(sTimerThread, &status);
+9 -32
View File
@@ -11,6 +11,7 @@
#include <net_stack.h> #include <net_stack.h>
class UserBuffer { class UserBuffer {
public: public:
UserBuffer(void* buffer, size_t size); UserBuffer(void* buffer, size_t size);
@@ -26,38 +27,13 @@ private:
}; };
// internal Fifo class which doesn't maintain it's own lock
class Fifo {
public:
Fifo(const char *name, size_t maxBytes);
~Fifo();
status_t InitCheck() const;
status_t Enqueue(net_buffer *buffer);
status_t EnqueueAndNotify(net_buffer *_buffer, net_socket *socket, uint8 event);
status_t Wait(mutex *lock, bigtime_t timeout);
net_buffer *Dequeue(bool clone);
status_t Clear();
void WakeAll();
bool IsEmpty() const { return current_bytes == 0; }
//private:
// these field names are kept so we can use templatized
// functions together with net_fifo
sem_id notify;
int32 waiting;
size_t max_bytes;
size_t current_bytes;
struct list buffers;
};
inline inline
UserBuffer::UserBuffer(void* buffer, size_t size) UserBuffer::UserBuffer(void* buffer, size_t size)
: fBuffer((uint8 *)buffer), fBufferSize(size), :
fAvailable(size), fStatus(B_OK) fBuffer((uint8*)buffer),
fBufferSize(size),
fAvailable(size),
fStatus(B_OK)
{ {
} }
@@ -90,13 +66,14 @@ status_t fifo_enqueue_buffer(net_fifo *fifo, struct net_buffer *buffer);
ssize_t fifo_dequeue_buffer(net_fifo* fifo, uint32 flags, bigtime_t timeout, ssize_t fifo_dequeue_buffer(net_fifo* fifo, uint32 flags, bigtime_t timeout,
struct net_buffer** _buffer); struct net_buffer** _buffer);
status_t clear_fifo(net_fifo* fifo); status_t clear_fifo(net_fifo* fifo);
status_t fifo_socket_enqueue_buffer(net_fifo *, net_socket *, uint8 event, status_t fifo_socket_enqueue_buffer(net_fifo* fifo, net_socket* socket,
net_buffer *); uint8 event, net_buffer* buffer);
// timer // timer
void init_timer(net_timer* timer, net_timer_func hook, void* data); void init_timer(net_timer* timer, net_timer_func hook, void* data);
void set_timer(net_timer* timer, bigtime_t delay); void set_timer(net_timer* timer, bigtime_t delay);
bool cancel_timer(struct net_timer* timer); bool cancel_timer(struct net_timer* timer);
void wait_for_timer(struct net_timer* timer);
bool is_timer_active(net_timer* timer); bool is_timer_active(net_timer* timer);
status_t init_timers(void); status_t init_timers(void);
void uninit_timers(void); void uninit_timers(void);