net_interface_private: added receive queue and splited device reading from packet processing. Delivering to self no longer is executed in the sender's context, which had some problems with TCP's locking.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21214 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos
2007-05-23 07:55:54 +00:00
parent 7e4dc23a7e
commit a1deb55ef5
6 changed files with 133 additions and 54 deletions
+109 -23
View File
@@ -21,6 +21,7 @@
#include <net/if_dl.h>
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -39,6 +40,51 @@ static uint32 sInterfaceIndex;
static uint32 sDeviceIndex;
static status_t
device_consumer_thread(void *_interface)
{
net_device_interface *interface = (net_device_interface *)_interface;
net_device *device = interface->device;
net_buffer *buffer;
while (true) {
ssize_t status = fifo_dequeue_buffer(&interface->receive_queue, 0,
B_INFINITE_TIMEOUT, &buffer);
if (status == B_INTERRUPTED)
continue;
else if (status < B_OK)
break;
if (buffer->interface != NULL) {
// if the interface is already specified this buffer was
// delivered locally.
net_domain *domain = buffer->interface->domain;
if (domain->module->receive_data(buffer) == B_OK)
buffer = NULL;
} else {
// find handler for this packet
DeviceHandlerList::Iterator it2 =
interface->receive_funcs.GetIterator();
while (buffer && it2.HasNext()) {
net_device_handler *handler = it2.Next();
// if the handler returns B_OK, it consumed the buffer
if (handler->type == buffer->type
&& handler->func(handler->cookie, device, buffer) == B_OK)
buffer = NULL;
}
}
if (buffer)
gNetBufferModule.free(buffer);
}
return B_OK;
}
static net_device_interface *
find_device_interface(const char *name)
{
@@ -65,6 +111,60 @@ domain_receive_adapter(void *cookie, net_device *device, net_buffer *buffer)
}
static net_device_interface *
allocate_device_interface(net_device *device, net_device_module_info *module)
{
net_device_interface *interface = new (std::nothrow) net_device_interface;
if (interface == NULL)
goto error_0;
if (recursive_lock_init(&interface->rx_lock, "rx lock") < B_OK)
goto error_1;
char name[128];
snprintf(name, sizeof(name), "%s receive queue", device->name);
if (init_fifo(&interface->receive_queue, name, 16 * 1024 * 1024) < B_OK)
goto error_2;
interface->name = device->name;
interface->module = module;
interface->device = device;
interface->up_count = 0;
interface->ref_count = 1;
interface->deframe_func = NULL;
interface->deframe_ref_count = 0;
snprintf(name, sizeof(name), "%s consumer", device->name);
interface->reader_thread = -1;
interface->consumer_thread = spawn_kernel_thread(device_consumer_thread,
name, B_REAL_TIME_DISPLAY_PRIORITY - 10, interface);
if (interface->consumer_thread < B_OK)
goto error_3;
resume_thread(interface->consumer_thread);
// TODO: proper interface index allocation
device->index = ++sDeviceIndex;
device->module = module;
sInterfaces.Add(interface);
return interface;
error_3:
uninit_fifo(&interface->receive_queue);
error_2:
recursive_lock_destroy(&interface->rx_lock);
error_1:
delete interface;
error_0:
return NULL;
}
net_device_interface *
grab_device_interface(net_device_interface *interface)
{
@@ -337,13 +437,15 @@ put_device_interface(struct net_device_interface *interface)
if (atomic_add(&interface->ref_count, -1) != 1)
return;
// we need to remove this interface!
{
BenaphoreLocker locker(sInterfaceLock);
sInterfaces.Remove(interface);
}
uninit_fifo(&interface->receive_queue);
status_t status;
wait_for_thread(interface->consumer_thread, &status);
interface->module->uninit_device(interface->device);
put_module(interface->module->info.name);
@@ -411,27 +513,9 @@ get_device_interface(const char *name, bool create)
net_device *device;
status_t status = module->init_device(name, &device);
if (status == B_OK) {
// create new module interface for this
interface = new (std::nothrow) net_device_interface;
if (interface != NULL) {
if (recursive_lock_init(&interface->rx_lock,
"rx lock") >= B_OK) {
interface->name = device->name;
interface->module = module;
interface->device = device;
interface->up_count = 0;
interface->ref_count = 1;
interface->deframe_func = NULL;
interface->deframe_ref_count = 0;
device->index = ++sDeviceIndex;
device->module = module;
sInterfaces.Add(interface);
return interface;
}
delete interface;
}
interface = allocate_device_interface(device, module);
if (interface)
return interface;
module->uninit_device(device);
}
put_module(moduleName);
@@ -469,6 +553,8 @@ down_device_interface(net_device_interface *interface)
thread_id reader_thread = interface->reader_thread;
// TODO when setting the interface down, should we clear the receive queue?
// one of the callers must hold a reference to the net_device_interface
// usually it is one of the net_interfaces.
recursive_lock_unlock(&interface->rx_lock);