Prepared net_device_monitor to accept device removal events.
- Introduced public net_device_monitor. - Changed the link protocol to maintain a lock per instance instead of inside the FIFO. Now all of the link instance data is protected. - Adapted the link protocol to use net_device_monitor. - Introduced a private Fifo class which doesn't maintain it's own lock. - Maybe we should add something like a public net_protocol_implementation which maintains a fifo and a benaphore? With the fifo using the structure's lock instead of maintaining it's own. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20614 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -37,6 +37,21 @@ struct net_timer {
|
|||||||
typedef int32 (*net_deframe_func)(struct net_device *device, struct net_buffer *buffer);
|
typedef int32 (*net_deframe_func)(struct net_device *device, struct net_buffer *buffer);
|
||||||
typedef status_t (*net_receive_func)(void *cookie, struct net_buffer *buffer);
|
typedef status_t (*net_receive_func)(void *cookie, struct net_buffer *buffer);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
B_DEVICE_GOING_UP = 1,
|
||||||
|
B_DEVICE_GOING_DOWN,
|
||||||
|
B_DEVICE_BEING_REMOVED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct net_device_monitor {
|
||||||
|
struct list_link link;
|
||||||
|
void *cookie;
|
||||||
|
|
||||||
|
status_t (*receive)(struct net_device_monitor *monitor,
|
||||||
|
struct net_buffer *buffer);
|
||||||
|
void (*event)(struct net_device_monitor *monitor, int32 event);
|
||||||
|
};
|
||||||
|
|
||||||
struct net_stack_module_info {
|
struct net_stack_module_info {
|
||||||
module_info info;
|
module_info info;
|
||||||
|
|
||||||
@@ -68,9 +83,9 @@ struct net_stack_module_info {
|
|||||||
status_t (*unregister_device_handler)(struct net_device *device, int32 type);
|
status_t (*unregister_device_handler)(struct net_device *device, int32 type);
|
||||||
|
|
||||||
status_t (*register_device_monitor)(struct net_device *device,
|
status_t (*register_device_monitor)(struct net_device *device,
|
||||||
net_receive_func receiveFunc, void *cookie);
|
struct net_device_monitor *monitor);
|
||||||
status_t (*unregister_device_monitor)(struct net_device *device,
|
status_t (*unregister_device_monitor)(struct net_device *device,
|
||||||
net_receive_func receiveFunc, void *cookie);
|
struct net_device_monitor *monitor);
|
||||||
|
|
||||||
status_t (*device_link_changed)(struct net_device *device);
|
status_t (*device_link_changed)(struct net_device *device);
|
||||||
status_t (*device_removed)(struct net_device *device);
|
status_t (*device_removed)(struct net_device *device);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ device_reader_thread(void *_interface)
|
|||||||
= interface->monitor_funcs.GetIterator();
|
= interface->monitor_funcs.GetIterator();
|
||||||
while (iterator.HasNext()) {
|
while (iterator.HasNext()) {
|
||||||
net_device_monitor *monitor = iterator.Next();
|
net_device_monitor *monitor = iterator.Next();
|
||||||
monitor->func(monitor->cookie, buffer);
|
monitor->receive(monitor, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 type = interface->deframe_func(device, buffer);
|
int32 type = interface->deframe_func(device, buffer);
|
||||||
@@ -478,7 +478,7 @@ interface_protocol_send_data(net_datalink_protocol *_protocol,
|
|||||||
interface->device_interface->monitor_funcs.GetIterator();
|
interface->device_interface->monitor_funcs.GetIterator();
|
||||||
while (iterator.HasNext()) {
|
while (iterator.HasNext()) {
|
||||||
net_device_monitor *monitor = iterator.Next();
|
net_device_monitor *monitor = iterator.Next();
|
||||||
monitor->func(monitor->cookie, buffer);
|
monitor->receive(monitor, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return protocol->device_module->send_data(protocol->device, buffer);
|
return protocol->device_module->send_data(protocol->device, buffer);
|
||||||
|
|||||||
@@ -593,9 +593,11 @@ unregister_device_handler(struct net_device *device, int32 type)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
register_device_monitor(struct net_device *device,
|
register_device_monitor(net_device *device, net_device_monitor *monitor)
|
||||||
net_receive_func receiveFunc, void *cookie)
|
|
||||||
{
|
{
|
||||||
|
if (monitor->receive == NULL || monitor->event == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
BenaphoreLocker locker(sInterfaceLock);
|
BenaphoreLocker locker(sInterfaceLock);
|
||||||
|
|
||||||
// find device interface for this device
|
// find device interface for this device
|
||||||
@@ -604,23 +606,13 @@ register_device_monitor(struct net_device *device,
|
|||||||
return ENODEV;
|
return ENODEV;
|
||||||
|
|
||||||
BenaphoreLocker _(interface->rx_lock);
|
BenaphoreLocker _(interface->rx_lock);
|
||||||
|
|
||||||
// Add new monitor
|
|
||||||
|
|
||||||
net_device_monitor *monitor = new (std::nothrow) net_device_monitor;
|
|
||||||
if (monitor == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
monitor->func = receiveFunc;
|
|
||||||
monitor->cookie = cookie;
|
|
||||||
interface->monitor_funcs.Add(monitor);
|
interface->monitor_funcs.Add(monitor);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
unregister_device_monitor(struct net_device *device,
|
unregister_device_monitor(net_device *device, net_device_monitor *monitor)
|
||||||
net_receive_func receiveFunc, void *cookie)
|
|
||||||
{
|
{
|
||||||
BenaphoreLocker locker(sInterfaceLock);
|
BenaphoreLocker locker(sInterfaceLock);
|
||||||
|
|
||||||
@@ -635,12 +627,8 @@ unregister_device_monitor(struct net_device *device,
|
|||||||
|
|
||||||
DeviceMonitorList::Iterator iterator = interface->monitor_funcs.GetIterator();
|
DeviceMonitorList::Iterator iterator = interface->monitor_funcs.GetIterator();
|
||||||
while (iterator.HasNext()) {
|
while (iterator.HasNext()) {
|
||||||
net_device_monitor *monitor = iterator.Next();
|
if (iterator.Next() == monitor) {
|
||||||
|
|
||||||
if (monitor->cookie == cookie && monitor->func == receiveFunc) {
|
|
||||||
// found it
|
|
||||||
iterator.Remove();
|
iterator.Remove();
|
||||||
delete monitor;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,10 @@ struct net_device_handler : public DoublyLinkedListLinkImpl<net_device_handler>
|
|||||||
void *cookie;
|
void *cookie;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct net_device_monitor : public DoublyLinkedListLinkImpl<net_device_monitor> {
|
|
||||||
net_receive_func func;
|
|
||||||
void *cookie;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef DoublyLinkedList<net_device_handler> DeviceHandlerList;
|
typedef DoublyLinkedList<net_device_handler> DeviceHandlerList;
|
||||||
typedef DoublyLinkedList<net_device_monitor> DeviceMonitorList;
|
|
||||||
|
typedef DoublyLinkedList<net_device_monitor,
|
||||||
|
DoublyLinkedListCLink<net_device_monitor> > DeviceMonitorList;
|
||||||
|
|
||||||
struct net_device_interface : DoublyLinkedListLinkImpl<net_device_interface> {
|
struct net_device_interface : DoublyLinkedListLinkImpl<net_device_interface> {
|
||||||
//struct list_link link;
|
//struct list_link link;
|
||||||
@@ -93,9 +90,9 @@ status_t register_device_handler(struct net_device *device, int32 type,
|
|||||||
net_receive_func receiveFunc, void *cookie);
|
net_receive_func receiveFunc, void *cookie);
|
||||||
status_t unregister_device_handler(struct net_device *device, int32 type);
|
status_t unregister_device_handler(struct net_device *device, int32 type);
|
||||||
status_t register_device_monitor(struct net_device *device,
|
status_t register_device_monitor(struct net_device *device,
|
||||||
net_receive_func receiveFunc, void *cookie);
|
struct net_device_monitor *monitor);
|
||||||
status_t unregister_device_monitor(struct net_device *device,
|
status_t unregister_device_monitor(struct net_device *device,
|
||||||
net_receive_func receiveFunc, void *cookie);
|
struct net_device_monitor *monitor);
|
||||||
status_t device_link_changed(net_device *device);
|
status_t device_link_changed(net_device *device);
|
||||||
status_t device_removed(net_device *device);
|
status_t device_removed(net_device *device);
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
#include <net_device.h>
|
#include <net_device.h>
|
||||||
|
|
||||||
|
#include <lock.h>
|
||||||
|
#include <util/AutoLock.h>
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
#include <net/if_types.h>
|
#include <net/if_types.h>
|
||||||
@@ -25,23 +28,173 @@
|
|||||||
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
||||||
|
|
||||||
|
|
||||||
struct link_protocol : net_protocol {
|
class LinkProtocol : public net_protocol {
|
||||||
net_fifo fifo;
|
public:
|
||||||
char registered_interface[IF_NAMESIZE];
|
LinkProtocol();
|
||||||
bool registered_monitor;
|
~LinkProtocol();
|
||||||
|
|
||||||
|
status_t InitCheck() const;
|
||||||
|
|
||||||
|
status_t StartMonitoring(const char *);
|
||||||
|
status_t StopMonitoring();
|
||||||
|
|
||||||
|
ssize_t ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer);
|
||||||
|
ssize_t ReadAvail() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _Enqueue(net_buffer *buffer);
|
||||||
|
status_t _Unregister();
|
||||||
|
|
||||||
|
mutable benaphore fLock;
|
||||||
|
Fifo fFifo;
|
||||||
|
|
||||||
|
net_device_monitor fMonitor;
|
||||||
|
net_device_interface *fMonitoredDevice;
|
||||||
|
|
||||||
|
static status_t _MonitorData(net_device_monitor *monitor, net_buffer *buffer);
|
||||||
|
static void _MonitorEvent(net_device_monitor *monitor, int32 event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct net_domain *sDomain;
|
struct net_domain *sDomain;
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
LinkProtocol::LinkProtocol()
|
||||||
link_monitor_data(void *cookie, net_buffer *packet)
|
: fFifo("packet monitor fifo", 65536)
|
||||||
{
|
{
|
||||||
link_protocol *protocol = (link_protocol *)cookie;
|
benaphore_init(&fLock, "packet monitor lock");
|
||||||
|
|
||||||
return fifo_socket_enqueue_buffer(&protocol->fifo, protocol->socket,
|
fMonitor.cookie = this;
|
||||||
B_SELECT_READ, packet);
|
fMonitor.receive = _MonitorData;
|
||||||
|
fMonitor.event = _MonitorEvent;
|
||||||
|
fMonitoredDevice = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LinkProtocol::~LinkProtocol()
|
||||||
|
{
|
||||||
|
if (fMonitoredDevice) {
|
||||||
|
unregister_device_monitor(fMonitoredDevice->device, &fMonitor);
|
||||||
|
put_device_interface(fMonitoredDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
benaphore_destroy(&fLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LinkProtocol::InitCheck() const
|
||||||
|
{
|
||||||
|
return fLock.sem >= 0 && fFifo.InitCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LinkProtocol::StartMonitoring(const char *deviceName)
|
||||||
|
{
|
||||||
|
BenaphoreLocker _(fLock);
|
||||||
|
|
||||||
|
if (fMonitoredDevice)
|
||||||
|
return B_BUSY;
|
||||||
|
|
||||||
|
net_device_interface *interface = get_device_interface(deviceName);
|
||||||
|
if (interface == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
status_t status = register_device_monitor(interface->device, &fMonitor);
|
||||||
|
if (status < B_OK) {
|
||||||
|
put_device_interface(interface);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
fMonitoredDevice = interface;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LinkProtocol::StopMonitoring()
|
||||||
|
{
|
||||||
|
BenaphoreLocker _(fLock);
|
||||||
|
|
||||||
|
// TODO compare our device with the supplied device name?
|
||||||
|
return _Unregister();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
LinkProtocol::ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer)
|
||||||
|
{
|
||||||
|
BenaphoreLocker _(fLock);
|
||||||
|
|
||||||
|
if (fMonitoredDevice == NULL) {
|
||||||
|
if (fFifo.current_bytes == 0)
|
||||||
|
return ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buffer *buffer;
|
||||||
|
status_t status = fFifo.Dequeue(&fLock, flags, socket->receive.timeout,
|
||||||
|
&buffer);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
*_buffer = buffer;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
LinkProtocol::ReadAvail() const
|
||||||
|
{
|
||||||
|
BenaphoreLocker _(fLock);
|
||||||
|
if (fMonitoredDevice == NULL)
|
||||||
|
return ECONNRESET;
|
||||||
|
return fFifo.current_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LinkProtocol::_Unregister()
|
||||||
|
{
|
||||||
|
if (fMonitoredDevice == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
status_t status = unregister_device_monitor(fMonitoredDevice->device,
|
||||||
|
&fMonitor);
|
||||||
|
put_device_interface(fMonitoredDevice);
|
||||||
|
fMonitoredDevice = NULL;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LinkProtocol::_Enqueue(net_buffer *buffer)
|
||||||
|
{
|
||||||
|
BenaphoreLocker _(fLock);
|
||||||
|
return fFifo.EnqueueAndNotify(buffer, socket, B_SELECT_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LinkProtocol::_MonitorData(net_device_monitor *monitor, net_buffer *packet)
|
||||||
|
{
|
||||||
|
return ((LinkProtocol *)monitor->cookie)->_Enqueue(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LinkProtocol::_MonitorEvent(net_device_monitor *monitor, int32 event)
|
||||||
|
{
|
||||||
|
LinkProtocol *protocol = (LinkProtocol *)monitor->cookie;
|
||||||
|
|
||||||
|
// We currently maintain the monitor while the device is down
|
||||||
|
if (event == B_DEVICE_BEING_REMOVED) {
|
||||||
|
BenaphoreLocker _(protocol->fLock);
|
||||||
|
|
||||||
|
protocol->_Unregister();
|
||||||
|
notify_socket(protocol->socket, B_SELECT_READ, ECONNRESET);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -51,35 +204,20 @@ link_monitor_data(void *cookie, net_buffer *packet)
|
|||||||
net_protocol *
|
net_protocol *
|
||||||
link_init_protocol(net_socket *socket)
|
link_init_protocol(net_socket *socket)
|
||||||
{
|
{
|
||||||
link_protocol *protocol = new (std::nothrow) link_protocol;
|
LinkProtocol *protocol = new (std::nothrow) LinkProtocol();
|
||||||
if (protocol == NULL)
|
if (protocol && protocol->InitCheck() < B_OK) {
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (init_fifo(&protocol->fifo, "packet monitor socket", 65536) < B_OK) {
|
|
||||||
delete protocol;
|
delete protocol;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol->registered_monitor = false;
|
|
||||||
return protocol;
|
return protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
link_uninit_protocol(net_protocol *_protocol)
|
link_uninit_protocol(net_protocol *protocol)
|
||||||
{
|
{
|
||||||
link_protocol *protocol = (link_protocol *)_protocol;
|
delete (LinkProtocol *)protocol;
|
||||||
|
|
||||||
if (protocol->registered_monitor) {
|
|
||||||
net_device_interface *interface = get_device_interface(protocol->registered_interface);
|
|
||||||
if (interface != NULL) {
|
|
||||||
unregister_device_monitor(interface->device, link_monitor_data, protocol);
|
|
||||||
put_device_interface(interface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uninit_fifo(&protocol->fifo);
|
|
||||||
delete protocol;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +261,9 @@ status_t
|
|||||||
link_control(net_protocol *_protocol, int level, int option, void *value,
|
link_control(net_protocol *_protocol, int level, int option, void *value,
|
||||||
size_t *_length)
|
size_t *_length)
|
||||||
{
|
{
|
||||||
link_protocol *protocol = (link_protocol *)_protocol;
|
LinkProtocol *protocol = (LinkProtocol *)_protocol;
|
||||||
|
|
||||||
|
// TODO All of this common functionality should be elsewhere
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case SIOCGIFINDEX:
|
case SIOCGIFINDEX:
|
||||||
@@ -203,58 +343,15 @@ link_control(net_protocol *_protocol, int level, int option, void *value,
|
|||||||
|
|
||||||
case SIOCSPACKETCAP:
|
case SIOCSPACKETCAP:
|
||||||
{
|
{
|
||||||
// start packet monitoring
|
|
||||||
|
|
||||||
if (protocol->registered_monitor)
|
|
||||||
return B_BUSY;
|
|
||||||
|
|
||||||
struct ifreq request;
|
struct ifreq request;
|
||||||
if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
|
if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
net_device_interface *interface = get_device_interface(request.ifr_name);
|
return protocol->StartMonitoring(request.ifr_name);
|
||||||
status_t status;
|
|
||||||
if (interface != NULL) {
|
|
||||||
status = register_device_monitor(interface->device,
|
|
||||||
link_monitor_data, protocol);
|
|
||||||
if (status == B_OK) {
|
|
||||||
// we're now registered
|
|
||||||
strlcpy(protocol->registered_interface, request.ifr_name, IF_NAMESIZE);
|
|
||||||
protocol->registered_monitor = true;
|
|
||||||
}
|
|
||||||
put_device_interface(interface);
|
|
||||||
} else
|
|
||||||
status = ENODEV;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SIOCCPACKETCAP:
|
case SIOCCPACKETCAP:
|
||||||
{
|
return protocol->StopMonitoring();
|
||||||
// stop packet monitoring
|
|
||||||
|
|
||||||
if (!protocol->registered_monitor)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
struct ifreq request;
|
|
||||||
if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
|
|
||||||
net_device_interface *interface = get_device_interface(request.ifr_name);
|
|
||||||
status_t status;
|
|
||||||
if (interface != NULL) {
|
|
||||||
status = unregister_device_monitor(interface->device,
|
|
||||||
link_monitor_data, protocol);
|
|
||||||
if (status == B_OK) {
|
|
||||||
// we're now no longer registered
|
|
||||||
protocol->registered_monitor = false;
|
|
||||||
}
|
|
||||||
put_device_interface(interface);
|
|
||||||
} else
|
|
||||||
status = ENODEV;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return datalink_control(sDomain, option, value, _length);
|
return datalink_control(sDomain, option, value, _length);
|
||||||
@@ -313,29 +410,17 @@ link_send_avail(net_protocol *protocol)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
link_read_data(net_protocol *_protocol, size_t numBytes, uint32 flags,
|
link_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
|
||||||
net_buffer **_buffer)
|
net_buffer **_buffer)
|
||||||
{
|
{
|
||||||
link_protocol *protocol = (link_protocol *)_protocol;
|
return ((LinkProtocol *)protocol)->ReadData(numBytes, flags, _buffer);
|
||||||
|
|
||||||
dprintf("link_read is waiting for data...\n");
|
|
||||||
|
|
||||||
net_buffer *buffer;
|
|
||||||
status_t status = fifo_dequeue_buffer(&protocol->fifo,
|
|
||||||
flags, protocol->socket->receive.timeout, &buffer);
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
*_buffer = buffer;
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
link_read_avail(net_protocol *_protocol)
|
link_read_avail(net_protocol *protocol)
|
||||||
{
|
{
|
||||||
link_protocol *protocol = (link_protocol *)_protocol;
|
return ((LinkProtocol *)protocol)->ReadAvail();
|
||||||
return protocol->fifo.current_bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,126 @@ static thread_id sTimerThread;
|
|||||||
static bigtime_t sTimerTimeout;
|
static bigtime_t sTimerTimeout;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename FifoType> static inline status_t
|
||||||
|
base_fifo_init(FifoType *fifo, const char *name, size_t maxBytes)
|
||||||
|
{
|
||||||
|
fifo->notify = create_sem(1, name);
|
||||||
|
fifo->max_bytes = maxBytes;
|
||||||
|
fifo->current_bytes = 0;
|
||||||
|
fifo->waiting = 0;
|
||||||
|
list_init(&fifo->buffers);
|
||||||
|
|
||||||
|
return fifo->notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename FifoType> static inline status_t
|
||||||
|
base_fifo_enqueue_buffer(FifoType *fifo, net_buffer *buffer)
|
||||||
|
{
|
||||||
|
if (fifo->max_bytes > 0 && fifo->current_bytes + buffer->size > fifo->max_bytes)
|
||||||
|
return ENOBUFS;
|
||||||
|
|
||||||
|
list_add_item(&fifo->buffers, buffer);
|
||||||
|
fifo->current_bytes += buffer->size;
|
||||||
|
|
||||||
|
if (fifo->waiting > 0) {
|
||||||
|
fifo->waiting--;
|
||||||
|
release_sem_etc(fifo->notify, 1, B_DO_NOT_RESCHEDULE);
|
||||||
|
// we still hold the benaphore lock, so it makes no sense
|
||||||
|
// to reschedule after having released the sync semaphore
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Gets the first buffer from the FIFO. If there is no buffer, it
|
||||||
|
will wait depending on the \a flags and \a timeout.
|
||||||
|
The following flags are supported (the rest is ignored):
|
||||||
|
MSG_DONTWAIT - ignores the timeout and never wait for a buffer; if your
|
||||||
|
socket is O_NONBLOCK, you should specify this flag. A \a timeout of
|
||||||
|
zero is equivalent to this flag, though.
|
||||||
|
MSG_PEEK - returns a clone of the buffer and keep the original
|
||||||
|
in the FIFO.
|
||||||
|
*/
|
||||||
|
template<typename FifoType> static inline ssize_t
|
||||||
|
base_fifo_dequeue_buffer(FifoType *fifo, benaphore *lock, uint32 flags,
|
||||||
|
bigtime_t timeout, net_buffer **_buffer)
|
||||||
|
{
|
||||||
|
// this function is called with `lock' held.
|
||||||
|
bool dontWait = (flags & MSG_DONTWAIT) != 0 || timeout == 0;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
net_buffer *buffer = (net_buffer *)list_get_first_item(&fifo->buffers);
|
||||||
|
if (buffer != NULL) {
|
||||||
|
if ((flags & MSG_PEEK) != 0) {
|
||||||
|
// we need to clone the buffer for inspection; we can't give a
|
||||||
|
// handle to a buffer that we're still using
|
||||||
|
buffer = gNetBufferModule.clone(buffer, false);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
status = B_NO_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list_remove_item(&fifo->buffers, buffer);
|
||||||
|
fifo->current_bytes -= buffer->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
*_buffer = buffer;
|
||||||
|
status = B_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dontWait)
|
||||||
|
fifo->waiting++;
|
||||||
|
|
||||||
|
// we need to wait until a new buffer becomes available
|
||||||
|
benaphore_unlock(lock);
|
||||||
|
|
||||||
|
if (dontWait)
|
||||||
|
return B_WOULD_BLOCK;
|
||||||
|
|
||||||
|
status = acquire_sem_etc(fifo->notify, 1,
|
||||||
|
B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, timeout);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// try again
|
||||||
|
benaphore_lock(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & MSG_PEEK) != 0 && fifo->waiting > 0) {
|
||||||
|
// another thread is waiting for data, since we didn't eat the
|
||||||
|
// buffer, it gets it
|
||||||
|
fifo->waiting--;
|
||||||
|
release_sem_etc(fifo->notify, 1, B_DO_NOT_RESCHEDULE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename FifoType> static inline status_t
|
||||||
|
base_fifo_clear(FifoType *fifo)
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
net_buffer *buffer = (net_buffer *)list_remove_head_item(&fifo->buffers);
|
||||||
|
if (buffer == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
gNetBufferModule.free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fifo->current_bytes = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
UserBuffer::Copy(void *source, size_t length)
|
UserBuffer::Copy(void *source, size_t length)
|
||||||
{
|
{
|
||||||
@@ -101,6 +221,65 @@ notify_socket(net_socket *socket, uint8 event, int32 value)
|
|||||||
// #pragma mark - FIFOs
|
// #pragma mark - FIFOs
|
||||||
|
|
||||||
|
|
||||||
|
Fifo::Fifo(const char *name, size_t maxBytes)
|
||||||
|
{
|
||||||
|
base_fifo_init(this, name, maxBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Fifo::~Fifo()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
delete_sem(notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Fifo::InitCheck() const
|
||||||
|
{
|
||||||
|
return !(notify < B_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Fifo::Enqueue(net_buffer *buffer)
|
||||||
|
{
|
||||||
|
return base_fifo_enqueue_buffer(this, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Fifo::EnqueueAndNotify(net_buffer *_buffer, net_socket *socket, uint8 event)
|
||||||
|
{
|
||||||
|
net_buffer *buffer = gNetBufferModule.clone(_buffer, false);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t status = Enqueue(buffer);
|
||||||
|
if (status < B_OK)
|
||||||
|
gNetBufferModule.free(buffer);
|
||||||
|
else
|
||||||
|
notify_socket(socket, event, current_bytes);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
Fifo::Dequeue(benaphore *lock, uint32 flags, bigtime_t timeout,
|
||||||
|
net_buffer **_buffer)
|
||||||
|
{
|
||||||
|
return base_fifo_dequeue_buffer(this, lock, flags, timeout, _buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
Fifo::Clear()
|
||||||
|
{
|
||||||
|
return base_fifo_clear(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
init_fifo(net_fifo *fifo, const char *name, size_t maxBytes)
|
init_fifo(net_fifo *fifo, const char *name, size_t maxBytes)
|
||||||
{
|
{
|
||||||
@@ -108,19 +287,11 @@ init_fifo(net_fifo *fifo, const char *name, size_t maxBytes)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
fifo->notify = create_sem(1, name);
|
status = base_fifo_init(fifo, name, maxBytes);
|
||||||
if (fifo->notify < B_OK) {
|
if (status < B_OK)
|
||||||
benaphore_destroy(&fifo->lock);
|
benaphore_destroy(&fifo->lock);
|
||||||
return fifo->notify;
|
|
||||||
}
|
|
||||||
|
|
||||||
fifo->max_bytes = maxBytes;
|
return status;
|
||||||
fifo->current_bytes = 0;
|
|
||||||
fifo->waiting = 0;
|
|
||||||
|
|
||||||
list_init(&fifo->buffers);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -134,99 +305,19 @@ uninit_fifo(net_fifo *fifo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
_fifo_enqueue_buffer(net_fifo *fifo, net_buffer *buffer)
|
|
||||||
{
|
|
||||||
if (fifo->max_bytes > 0 && fifo->current_bytes + buffer->size > fifo->max_bytes)
|
|
||||||
return ENOBUFS;
|
|
||||||
|
|
||||||
list_add_item(&fifo->buffers, buffer);
|
|
||||||
fifo->current_bytes += buffer->size;
|
|
||||||
|
|
||||||
if (fifo->waiting > 0) {
|
|
||||||
fifo->waiting--;
|
|
||||||
release_sem_etc(fifo->notify, 1, B_DO_NOT_RESCHEDULE);
|
|
||||||
// we still hold the benaphore lock, so it makes no sense
|
|
||||||
// to reschedule after having released the sync semaphore
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
fifo_enqueue_buffer(net_fifo *fifo, net_buffer *buffer)
|
fifo_enqueue_buffer(net_fifo *fifo, net_buffer *buffer)
|
||||||
{
|
{
|
||||||
BenaphoreLocker locker(fifo->lock);
|
BenaphoreLocker locker(fifo->lock);
|
||||||
return _fifo_enqueue_buffer(fifo, buffer);
|
return base_fifo_enqueue_buffer(fifo, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
ssize_t fifo_dequeue_buffer(net_fifo *fifo, uint32 flags, bigtime_t timeout,
|
||||||
Gets the first buffer from the FIFO. If there is no buffer, it
|
struct net_buffer **_buffer)
|
||||||
will wait depending on the \a flags and \a timeout.
|
|
||||||
The following flags are supported (the rest is ignored):
|
|
||||||
MSG_DONTWAIT - ignores the timeout and never wait for a buffer; if your
|
|
||||||
socket is O_NONBLOCK, you should specify this flag. A \a timeout of
|
|
||||||
zero is equivalent to this flag, though.
|
|
||||||
MSG_PEEK - returns a clone of the buffer and keep the original
|
|
||||||
in the FIFO.
|
|
||||||
*/
|
|
||||||
ssize_t
|
|
||||||
fifo_dequeue_buffer(net_fifo *fifo, uint32 flags, bigtime_t timeout,
|
|
||||||
net_buffer **_buffer)
|
|
||||||
{
|
{
|
||||||
benaphore_lock(&fifo->lock);
|
BenaphoreLocker locker(fifo->lock);
|
||||||
bool dontWait = (flags & MSG_DONTWAIT) != 0 || timeout == 0;
|
return base_fifo_dequeue_buffer(fifo, &fifo->lock, flags, timeout, _buffer);
|
||||||
status_t status;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
net_buffer *buffer = (net_buffer *)list_get_first_item(&fifo->buffers);
|
|
||||||
if (buffer != NULL) {
|
|
||||||
if ((flags & MSG_PEEK) != 0) {
|
|
||||||
// we need to clone the buffer for inspection; we can't give a
|
|
||||||
// handle to a buffer that we're still using
|
|
||||||
buffer = gNetBufferModule.clone(buffer, false);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
status = B_NO_MEMORY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list_remove_item(&fifo->buffers, buffer);
|
|
||||||
fifo->current_bytes -= buffer->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
*_buffer = buffer;
|
|
||||||
status = B_OK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dontWait)
|
|
||||||
fifo->waiting++;
|
|
||||||
|
|
||||||
// we need to wait until a new buffer becomes available
|
|
||||||
benaphore_unlock(&fifo->lock);
|
|
||||||
|
|
||||||
if (dontWait)
|
|
||||||
return B_WOULD_BLOCK;
|
|
||||||
|
|
||||||
status = acquire_sem_etc(fifo->notify, 1,
|
|
||||||
B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, timeout);
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
// try again
|
|
||||||
benaphore_lock(&fifo->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flags & MSG_PEEK) != 0 && fifo->waiting > 0) {
|
|
||||||
// another thread is waiting for data, since we didn't eat the
|
|
||||||
// buffer, it gets it
|
|
||||||
fifo->waiting--;
|
|
||||||
release_sem_etc(fifo->notify, 1, B_DO_NOT_RESCHEDULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
benaphore_unlock(&fifo->lock);
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -234,17 +325,7 @@ status_t
|
|||||||
clear_fifo(net_fifo *fifo)
|
clear_fifo(net_fifo *fifo)
|
||||||
{
|
{
|
||||||
BenaphoreLocker locker(fifo->lock);
|
BenaphoreLocker locker(fifo->lock);
|
||||||
|
return base_fifo_clear(fifo);
|
||||||
while (true) {
|
|
||||||
net_buffer *buffer = (net_buffer *)list_remove_head_item(&fifo->buffers);
|
|
||||||
if (buffer == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
gNetBufferModule.free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
fifo->current_bytes = 0;
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -258,7 +339,7 @@ fifo_socket_enqueue_buffer(net_fifo *fifo, net_socket *socket, uint8 event,
|
|||||||
|
|
||||||
BenaphoreLocker locker(fifo->lock);
|
BenaphoreLocker locker(fifo->lock);
|
||||||
|
|
||||||
status_t status = _fifo_enqueue_buffer(fifo, buffer);
|
status_t status = base_fifo_enqueue_buffer(fifo, buffer);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
gNetBufferModule.free(buffer);
|
gNetBufferModule.free(buffer);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -26,6 +26,33 @@ 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);
|
||||||
|
|
||||||
|
ssize_t Dequeue(benaphore *lock, uint32 flags, bigtime_t timeout,
|
||||||
|
net_buffer **_buffer);
|
||||||
|
status_t Clear();
|
||||||
|
|
||||||
|
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),
|
: fBuffer((uint8 *)buffer), fBufferSize(size),
|
||||||
|
|||||||
Reference in New Issue
Block a user