Rename net_data into net_buffer, which make more sense.
Add read_buffer() and write_buffer() to access/modify net_buffer data chunks. Add a split_buffer() function, that will split at a specified offset. To be implemented. Remove append_buffer(), prepend_buffer() and insert_buffer(), replace by all-purpose add_to_buffer(). Rename remove_buffer() into remove_from_buffer(), to opposite add_to_buffer() git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3322 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
4f09fa2ff1
commit
d5b2863194
@ -1,932 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <KernelExport.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include "memory_pool.h"
|
||||
#include "net_stack.h"
|
||||
#include "data.h"
|
||||
|
||||
#if 0
|
||||
typedef struct net_data_node_info
|
||||
{
|
||||
uint32 ref_count; // this data is referenced by 'ref_count' net_data_node(s)
|
||||
const void * data; // address of data
|
||||
uint32 len; // in bytes (could be 0, with *guest* add_free_element() node
|
||||
data_node_free_func free_func; // if NULL, don't free it!
|
||||
void * free_cookie; // if != NULL, free_func(cookie, data) is called... otherwise, free_func(data)
|
||||
} net_data_node_info;
|
||||
|
||||
|
||||
typedef struct net_data_node
|
||||
{
|
||||
struct net_data_node * next;
|
||||
net_data_node_info * info;
|
||||
} net_data_node;
|
||||
#endif
|
||||
|
||||
typedef struct net_data_node
|
||||
{
|
||||
struct net_data_node *next;
|
||||
struct net_data_node *next_data;
|
||||
uint32 ref_count; // this data is referenced by 'ref_count' net_data_node(s)
|
||||
const void *data; // address of data
|
||||
uint32 len; // in bytes (could be 0, with *guest* add_data_free_element() node
|
||||
data_node_free_func free_func; // if NULL, don't free it!
|
||||
void * free_cookie; // if != NULL, free_func(cookie, data) is called... otherwise, free_func(data)
|
||||
} net_data_node;
|
||||
|
||||
struct net_data {
|
||||
struct net_data *next; // for chained datas, like fifo'ed ones...
|
||||
struct net_data_node *node_list; // unordored but ref counted net_data_node(s) linked list, to free on delete_data()
|
||||
struct net_data_node *data_list; // ordered net_data_node(s) linked list
|
||||
size_t len; // total bytes in this net_data
|
||||
uint32 flags;
|
||||
#define DATA_TO_FREE (1)
|
||||
#define DATA_IS_URGENT (2)
|
||||
};
|
||||
|
||||
struct net_data_queue
|
||||
{
|
||||
benaphore lock;
|
||||
sem_id sync;
|
||||
volatile int32 waiting;
|
||||
volatile int32 interrupt;
|
||||
|
||||
size_t max_bytes;
|
||||
size_t current_bytes;
|
||||
|
||||
net_data *head;
|
||||
net_data *tail;
|
||||
};
|
||||
|
||||
|
||||
#define DPRINTF printf
|
||||
|
||||
#define DATAS_PER_POOL (64)
|
||||
#define DATA_NODES_PER_POOL (256)
|
||||
|
||||
static memory_pool * g_datas_pool = NULL;
|
||||
static memory_pool * g_datas_nodes_pool = NULL;
|
||||
|
||||
static thread_id g_datas_purgatory_thread = -1;
|
||||
static sem_id g_datas_purgatory_sync = -1; // use to notify data purgatory thread that some net_data nodes need to be deleted (interrupt safely...)
|
||||
|
||||
#define DATA_QUEUES_PER_POOL 16
|
||||
|
||||
static memory_pool * g_datas_queues_pool = NULL;
|
||||
|
||||
extern struct memory_pool_module_info *g_memory_pool;
|
||||
|
||||
// Privates prototypes
|
||||
// -------------------
|
||||
|
||||
static net_data_node * new_data_node(const void *data, uint32 len);
|
||||
static net_data_node * find_data_node(net_data *data, uint32 offset, uint32 *offset_in_node, net_data_node **previous_node);
|
||||
|
||||
static int32 datas_purgatory_thread(void * data);
|
||||
|
||||
static status_t data_death(memory_pool * pool, void * node, void * cookie);
|
||||
static status_t data_queue_death(memory_pool * pool, void * node, void * cookie);
|
||||
|
||||
|
||||
// LET'S GO FOR IMPLEMENTATION
|
||||
// ------------------------------------
|
||||
|
||||
|
||||
// #pragma mark [Start/Stop Service functions]
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t start_data_service()
|
||||
{
|
||||
g_datas_purgatory_sync = create_sem(0, "net data purgatory");
|
||||
#ifdef _KERNEL_MODE
|
||||
set_sem_owner(g_datas_purgatory_sync, B_SYSTEM_TEAM);
|
||||
#endif
|
||||
|
||||
// fire data_purgatory_thread
|
||||
g_datas_purgatory_thread = spawn_kernel_thread(datas_purgatory_thread, "net data serial killer", B_LOW_PRIORITY, 0);
|
||||
if (g_datas_purgatory_thread < B_OK)
|
||||
return g_datas_purgatory_thread;
|
||||
|
||||
puts("net data service started.");
|
||||
|
||||
return resume_thread(g_datas_purgatory_thread);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t stop_data_service()
|
||||
{
|
||||
status_t status;
|
||||
|
||||
// Free all data queues inner stuff (sem, locker, etc)
|
||||
g_memory_pool->for_each_pool_node(g_datas_queues_pool, data_queue_death, NULL);
|
||||
g_memory_pool->delete_pool(g_datas_queues_pool);
|
||||
g_datas_queues_pool = NULL;
|
||||
|
||||
// this would stop data_purgatory_thread
|
||||
delete_sem(g_datas_purgatory_sync);
|
||||
g_datas_purgatory_sync = -1;
|
||||
wait_for_thread(g_datas_purgatory_thread, &status);
|
||||
|
||||
// As the purgatory thread stop, some net_data(s) still could be flagged
|
||||
// data_TO_FREE, but not deleted... yet.
|
||||
g_memory_pool->for_each_pool_node(g_datas_pool, data_death, NULL);
|
||||
|
||||
// free datas-related pools
|
||||
g_memory_pool->delete_pool(g_datas_pool);
|
||||
g_memory_pool->delete_pool(g_datas_nodes_pool);
|
||||
|
||||
g_datas_pool = NULL;
|
||||
g_datas_nodes_pool = NULL;
|
||||
|
||||
puts("net data service stopped.");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark [Public functions]
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
net_data * new_data(void)
|
||||
{
|
||||
net_data *nd;
|
||||
|
||||
if (! g_datas_pool)
|
||||
g_datas_pool = g_memory_pool->new_pool(sizeof(net_data), DATAS_PER_POOL);
|
||||
|
||||
if (! g_datas_pool)
|
||||
return NULL;
|
||||
|
||||
nd = (net_data *) g_memory_pool->new_pool_node(g_datas_pool);
|
||||
if (! nd)
|
||||
return NULL;
|
||||
|
||||
nd->next = NULL;
|
||||
nd->data_list = NULL;
|
||||
nd->node_list = NULL;
|
||||
nd->len = 0;
|
||||
nd->flags = 0;
|
||||
|
||||
return nd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t delete_data(net_data *nd, bool interrupt_safe)
|
||||
{
|
||||
net_data_node *node;
|
||||
net_data_node *next_node;
|
||||
|
||||
if (! nd)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (! g_datas_pool)
|
||||
// Uh? From where come this net_data!?!
|
||||
return B_ERROR;
|
||||
|
||||
if (interrupt_safe) {
|
||||
// We're called from a interrupt handler. Don't use any blocking calls (delete_pool_node() is!)
|
||||
// We flag this net_data as to be free by the data purgatory thread
|
||||
// Notify him that he have a new data purgatory member
|
||||
// (notice the B_DO_NOT_RESCHEDULE usage, the only release_sem_etc() interrupt-safe mode)
|
||||
nd->flags |= DATA_TO_FREE;
|
||||
// release_sem_etc(g_data_purgatory_sync, 1, B_DO_NOT_RESCHEDULE);
|
||||
return B_OK;
|
||||
};
|
||||
|
||||
// Okay, we can free each data node in the node_list right now!
|
||||
node = nd->node_list;
|
||||
while (node) {
|
||||
// okay, one net_data_node less referencing this data
|
||||
node->ref_count--;
|
||||
next_node = node->next;
|
||||
|
||||
if (node->ref_count == 0) {
|
||||
// it was the last net_data_node to reference this data,
|
||||
// so free it now!
|
||||
|
||||
// do we have to call the free_func() on this data?
|
||||
if (node->free_func) {
|
||||
// yes, please!!!
|
||||
// call the right free_func on this data
|
||||
if (node->free_cookie)
|
||||
node->free_func(node->free_cookie, (void *) node->data);
|
||||
else
|
||||
node->free_func((void *) node->data);
|
||||
};
|
||||
};
|
||||
// delete this net_data_node
|
||||
g_memory_pool->delete_pool_node(g_datas_nodes_pool, node);
|
||||
|
||||
node = next_node;
|
||||
};
|
||||
|
||||
// Last, delete the net_data itself
|
||||
return g_memory_pool->delete_pool_node(g_datas_pool, nd);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
net_data * duplicate_data(net_data *nd)
|
||||
{
|
||||
return NULL; // B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
net_data * clone_data(net_data *nd)
|
||||
{
|
||||
return NULL; // B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t add_data_free_node(net_data *nd, void *arg1, void *arg2, data_node_free_func freethis)
|
||||
{
|
||||
net_data_node *node;
|
||||
|
||||
if (! nd)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
node = new_data_node(arg1, 0); // unknown data length
|
||||
if (! node)
|
||||
return B_ERROR;
|
||||
|
||||
node->next_data = NULL; // not a data_list member, just a *guest star* node_list member
|
||||
node->free_func = freethis;
|
||||
node->free_cookie = arg2;
|
||||
|
||||
// add to node_list (nodes order don't matter in this list :-)
|
||||
node->next = nd->node_list;
|
||||
nd->node_list = node;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t prepend_data(net_data *nd, const void *data, uint32 bytes, data_node_free_func freethis)
|
||||
{
|
||||
net_data_node *node;
|
||||
|
||||
if (! nd)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (bytes < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// create a new node to host the prepending data
|
||||
node = new_data_node(data, bytes);
|
||||
if (! node)
|
||||
return B_ERROR;
|
||||
|
||||
node->free_func = freethis; // can be NULL = don't free this chunk
|
||||
node->free_cookie = NULL;
|
||||
|
||||
// add this node to node_list (nodes order don't matter in this list, so we do it the easy way :-)
|
||||
node->next = nd->node_list;
|
||||
nd->node_list = node;
|
||||
|
||||
// prepend this node to the data_list:
|
||||
node->next_data = nd->data_list;
|
||||
nd->data_list = node;
|
||||
|
||||
nd->len += bytes;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t append_data(net_data *nd, const void *data, uint32 bytes, data_node_free_func freethis)
|
||||
{
|
||||
net_data_node *node;
|
||||
|
||||
if (! nd)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (bytes < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// create a new node to host the appending data
|
||||
node = new_data_node(data, bytes);
|
||||
if (! node)
|
||||
return B_ERROR;
|
||||
|
||||
node->free_func = freethis; // can be NULL = don't free this chunk
|
||||
node->free_cookie = NULL;
|
||||
|
||||
// add this node to node_list (nodes order don't matter in this list, so we do it the easy way :-)
|
||||
node->next = nd->node_list;
|
||||
nd->node_list = node;
|
||||
|
||||
// Add this node to the end of data_list
|
||||
node->next_data = NULL;
|
||||
if (nd->data_list) {
|
||||
net_data_node *tmp;
|
||||
|
||||
tmp = nd->data_list;
|
||||
while(tmp->next_data) // search the last net_data_node in list
|
||||
tmp = tmp->next_data;
|
||||
tmp->next_data = node;
|
||||
} else
|
||||
nd->data_list = node;
|
||||
|
||||
nd->len += bytes;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t insert_data(net_data *nd, uint32 offset, const void *data, uint32 bytes, data_node_free_func freethis)
|
||||
{
|
||||
net_data_node *previous_node;
|
||||
net_data_node *next_node;
|
||||
net_data_node *split_node;
|
||||
net_data_node *new_node;
|
||||
uint32 offset_in_node;
|
||||
|
||||
if (! nd)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (bytes < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (offset == 0)
|
||||
return prepend_data(nd, data, bytes, freethis);
|
||||
|
||||
next_node = find_data_node(nd, offset, &offset_in_node, &previous_node);
|
||||
if (! next_node)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
split_node = NULL;
|
||||
new_node = NULL;
|
||||
|
||||
if (offset_in_node) {
|
||||
// we must split next_node data chunk in two parts :-(
|
||||
uint8 *split;
|
||||
|
||||
split = (uint8 *) next_node->data;
|
||||
split += offset_in_node;
|
||||
split_node = new_data_node(split, next_node->len - offset_in_node);
|
||||
if (! split_node)
|
||||
goto error1;
|
||||
|
||||
next_node->len = offset_in_node; // cut the data len of original node
|
||||
|
||||
// as split_node data comes from 'next_node', we don't
|
||||
// ask to free this node data, as it would be by the next_node node
|
||||
split_node->free_func = NULL;
|
||||
|
||||
// add the split_node to node_list (nodes order don't matter in this list, so we do it the easy way :-)
|
||||
split_node->next = nd->node_list;
|
||||
nd->node_list = split_node;
|
||||
|
||||
// insert the split_node between the two part of the *splitted* next_node
|
||||
split_node->next_data = next_node->next_data;
|
||||
next_node->next_data = split_node;
|
||||
|
||||
previous_node = next_node;
|
||||
next_node = split_node;
|
||||
};
|
||||
|
||||
// create a new node to host inserted data
|
||||
new_node = new_data_node(data, bytes);
|
||||
if (! new_node)
|
||||
goto error2;
|
||||
|
||||
new_node->free_func = freethis; // can be NULL = don't free this chunk
|
||||
new_node->free_cookie = NULL;
|
||||
|
||||
// add the new_node to node_list (nodes order don't matter in this list, so we do it the easy way :-)
|
||||
new_node->next = nd->node_list;
|
||||
nd->node_list = new_node;
|
||||
|
||||
// Insert this new_node between previous and next node
|
||||
previous_node->next_data = new_node;
|
||||
new_node->next_data = next_node;
|
||||
|
||||
nd->len += bytes;
|
||||
|
||||
return B_OK;
|
||||
|
||||
error2:
|
||||
g_memory_pool->delete_pool_node(g_datas_nodes_pool, new_node);
|
||||
error1:
|
||||
g_memory_pool->delete_pool_node(g_datas_nodes_pool, split_node);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t remove_data(net_data *nd, uint32 offset, uint32 bytes)
|
||||
{
|
||||
#if 0
|
||||
// TODO!!!
|
||||
|
||||
net_data_node * ndn;
|
||||
net_data_node * start_node;
|
||||
net_data_node * end_node;
|
||||
uint32 start_node_offset;
|
||||
uint32 end_node_offset;
|
||||
net_data_node * start_split_node;
|
||||
net_data_node * end_split_node;
|
||||
uint8 * data;
|
||||
|
||||
if (bytes < 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
/*
|
||||
Possibles cases:
|
||||
[XXXXXXX|++++++].... Triming at start of node (start and/or end nodes)
|
||||
[+++|XXXXXX|+++].... Triming in the middle of *one* node
|
||||
[+++++|XXXXXXXX].... Triming at the end of start node
|
||||
...[XXXXXXXXXXXXXX].... Triming one full node
|
||||
*/
|
||||
|
||||
start_node = find_data_node(nd, offset, &start_node_offset, NULL);
|
||||
if (! start_node)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
end_node = find_data_node(nd, offset + bytes, &end_node_offset, NULL);
|
||||
if (! end_node)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if ( (start_node == end_node) &&
|
||||
(start_node_offset > 0) && (end_node_offset != end_node->len) )
|
||||
// need to split one node into two parts, left & right, to be able to
|
||||
// trim data in the middle:
|
||||
// [++++|XXXXXX|+++++++]
|
||||
return B_OK;
|
||||
};
|
||||
|
||||
// if the trimmed part is in one node, we know now that it's:
|
||||
// |++++++|XXXXXXXXXXXX|, or:
|
||||
// |XXXXXXXXX|+++++++++|
|
||||
|
||||
if (start_node_offset)
|
||||
start_node->len = start_node_offset;
|
||||
|
||||
if (end_node_offset) {
|
||||
data = (uint8 *) end_node->data;
|
||||
data += end_node_offset;
|
||||
end_node->data = data;
|
||||
end_node->len -= end_node_offset;
|
||||
};
|
||||
|
||||
// start node must be split
|
||||
split = (uint8 *) start_node->data;
|
||||
split += start_node_offset;
|
||||
start_split_node = new_data_node(split, start_node->len - start_node_offset);
|
||||
if (! start_split_node)
|
||||
goto error1;
|
||||
};
|
||||
|
||||
if (end_node_offset) {
|
||||
// end node must be split
|
||||
split = (uint8 *) end_node->data;
|
||||
split += end_node_offset;
|
||||
end_split_node = new_data_node(split, end_node->len - end_node_offset);
|
||||
if (! end_split_node)
|
||||
goto error2;
|
||||
};
|
||||
|
||||
if (start_split_node) {
|
||||
};
|
||||
|
||||
ndn = start_node->next_data;
|
||||
while (ndn->next_data != end_node) {
|
||||
if (ndn->next_data == end_node)
|
||||
break;
|
||||
|
||||
ndn = ndn->next_data;
|
||||
};
|
||||
!= end_node
|
||||
|
||||
if (end_split_node) {
|
||||
};
|
||||
|
||||
|
||||
// split start_node data chunk in two parts
|
||||
start_node->len = start_node_offset;
|
||||
|
||||
start_split_node->free_func = NULL;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
ndn->len = offset_in_node;
|
||||
|
||||
split_node->free_func = NULL; // as split_node data comes from 'ndn', we don't
|
||||
// free this node data but only 'ndn' one...
|
||||
|
||||
// create a new node to host inserted data
|
||||
new_node = new_data_node(data, bytes);
|
||||
if (! new_node)
|
||||
goto error2;
|
||||
|
||||
new_node->free_func = freethis; // can be NULL = don't free this chunk
|
||||
new_node->free_cookie = NULL;
|
||||
|
||||
// add these nodes to node_list (nodes order don't matter in this list, so we do it the easy way :-)
|
||||
split_node->next = nd->node_list;
|
||||
new_node->next = split_node;
|
||||
nd->node_list = new_node;
|
||||
|
||||
// Insert this new_node this node to the end of data_list
|
||||
split_node->next_data = ndn->next_data;
|
||||
ndn->next_data = new_node;
|
||||
new_node->next_data = split_node;
|
||||
|
||||
nd->len -= bytes;
|
||||
|
||||
return B_OK;
|
||||
|
||||
error2:
|
||||
g_memory_pool->delete_pool_node(g_datas_nodes_pool, end_split_node);
|
||||
error1:
|
||||
if (start_split_node)
|
||||
g_memory_pool->delete_pool_node(g_datas_nodes_pool, start_split_node);
|
||||
#endif
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
uint32 copy_from_data(net_data *data, uint32 offset, void *copyinto, uint32 bytes)
|
||||
{
|
||||
net_data_node *node;
|
||||
uint32 offset_in_node;
|
||||
uint32 len;
|
||||
uint32 chunk_len;
|
||||
uint8 *from;
|
||||
uint8 *to;
|
||||
|
||||
to = (uint8 *) copyinto;
|
||||
len = 0;
|
||||
|
||||
node = find_data_node(data, offset, &offset_in_node, NULL);
|
||||
while (node) {
|
||||
from = (uint8 *) node->data;
|
||||
from += offset_in_node;
|
||||
chunk_len = min((node->len - offset_in_node), (bytes - len));
|
||||
|
||||
memcpy(to, from, chunk_len);
|
||||
|
||||
len += chunk_len;
|
||||
if (len >= bytes)
|
||||
break;
|
||||
|
||||
to += chunk_len;
|
||||
offset_in_node = 0; // only the first node
|
||||
|
||||
node = node->next_data; // next node
|
||||
};
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// #pragma mark [data(s) queues functions]
|
||||
|
||||
// --------------------------------------------------
|
||||
net_data_queue * new_data_queue(size_t max_bytes)
|
||||
{
|
||||
net_data_queue *queue;
|
||||
|
||||
if (! g_datas_queues_pool)
|
||||
g_datas_queues_pool = g_memory_pool->new_pool(sizeof(net_data_queue), DATA_QUEUES_PER_POOL);
|
||||
|
||||
if (! g_datas_queues_pool)
|
||||
return NULL;
|
||||
|
||||
queue = (net_data_queue *) g_memory_pool->new_pool_node(g_datas_queues_pool);
|
||||
if (! queue)
|
||||
return NULL;
|
||||
|
||||
create_benaphore(&queue->lock, "net_data_queue lock");
|
||||
queue->sync = create_sem(0, "net_data_queue sem");
|
||||
|
||||
queue->max_bytes = max_bytes;
|
||||
queue->current_bytes = 0;
|
||||
|
||||
queue->head = queue->tail = NULL;
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t delete_data_queue(net_data_queue *queue)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
if (! queue)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (! g_datas_queues_pool)
|
||||
// Uh? From where come this queue then!?!
|
||||
return B_ERROR;
|
||||
|
||||
// free the net_data's (sill) in this queue
|
||||
status = empty_data_queue(queue);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
delete_sem(queue->sync);
|
||||
delete_benaphore(&queue->lock);
|
||||
|
||||
return g_memory_pool->delete_pool_node(g_datas_queues_pool, queue);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t empty_data_queue(net_data_queue *queue)
|
||||
{
|
||||
net_data *data;
|
||||
net_data *tmp = NULL;
|
||||
|
||||
if (! queue)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
lock_benaphore(&queue->lock);
|
||||
|
||||
data = queue->head;
|
||||
while (data) {
|
||||
tmp = data;
|
||||
data = data->next;
|
||||
delete_data(data, true);
|
||||
};
|
||||
|
||||
queue->head = NULL;
|
||||
queue->tail = NULL;
|
||||
|
||||
delete_sem(queue->sync);
|
||||
queue->sync = create_sem(0, "net_data_queue sem");
|
||||
|
||||
unlock_benaphore(&queue->lock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t enqueue_data(net_data_queue *queue, net_data *data)
|
||||
{
|
||||
if (! queue)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (! data)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
data->next = NULL;
|
||||
|
||||
/*
|
||||
if (queue->current_bytes + data->len > queue->max_bytes)
|
||||
// what to do? dump some enqueued data(s) to free space? drop the new net_data?
|
||||
// TODO: dequeue enought net_data(s) to free space to queue this one...
|
||||
NULL;
|
||||
*/
|
||||
lock_benaphore(&queue->lock);
|
||||
|
||||
if (! queue->head)
|
||||
queue->head = data;
|
||||
if (queue->tail)
|
||||
queue->tail->next = data;
|
||||
queue->tail = data;
|
||||
|
||||
queue->current_bytes += data->len;
|
||||
|
||||
unlock_benaphore(&queue->lock);
|
||||
|
||||
return release_sem_etc(queue->sync, 1, B_DO_NOT_RESCHEDULE);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
size_t dequeue_data(net_data_queue *queue, net_data **data, bigtime_t timeout, bool peek)
|
||||
{
|
||||
status_t status;
|
||||
net_data *head_data;
|
||||
|
||||
if (! queue)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
status = acquire_sem_etc(queue->sync, 1, B_RELATIVE_TIMEOUT, timeout);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
lock_benaphore(&queue->lock);
|
||||
|
||||
head_data = queue->head;
|
||||
|
||||
if (! peek) {
|
||||
// detach the head net_data from this fifo
|
||||
queue->head = head_data->next;
|
||||
if (queue->tail == head_data)
|
||||
queue->tail = queue->head;
|
||||
|
||||
queue->current_bytes -= head_data->len;
|
||||
|
||||
head_data->next = NULL; // we never know :-)
|
||||
};
|
||||
|
||||
unlock_benaphore(&queue->lock);
|
||||
|
||||
*data = head_data;
|
||||
|
||||
return head_data->len;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark [Helper functions]
|
||||
|
||||
// --------------------------------------------------
|
||||
static net_data_node * new_data_node(const void *data, uint32 len)
|
||||
{
|
||||
net_data_node * node;
|
||||
|
||||
if (! g_datas_nodes_pool)
|
||||
g_datas_nodes_pool = g_memory_pool->new_pool(sizeof(net_data_node), DATA_NODES_PER_POOL);
|
||||
|
||||
if (! g_datas_nodes_pool)
|
||||
return NULL;
|
||||
|
||||
node = (net_data_node *) g_memory_pool->new_pool_node(g_datas_nodes_pool);
|
||||
|
||||
node->data = data;
|
||||
node->len = len;
|
||||
|
||||
node->ref_count = 1;
|
||||
|
||||
node->free_cookie = NULL;
|
||||
node->free_func = NULL;
|
||||
|
||||
node->next = NULL;
|
||||
node->next_data = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
static net_data_node * find_data_node(net_data *data, uint32 offset, uint32 *offset_in_node, net_data_node **previous_node)
|
||||
{
|
||||
net_data_node *previous;
|
||||
net_data_node *node;
|
||||
uint32 len;
|
||||
|
||||
if (! data)
|
||||
return NULL;
|
||||
|
||||
if (data->len <= offset)
|
||||
// this net_data don't hold enough data to reach this offset!
|
||||
return NULL;
|
||||
|
||||
len = 0;
|
||||
node = data->data_list;
|
||||
previous = NULL;
|
||||
while (node) {
|
||||
len += node->len;
|
||||
|
||||
if(offset < len)
|
||||
break;
|
||||
|
||||
previous = node;
|
||||
node = node->next_data;
|
||||
};
|
||||
|
||||
if (offset_in_node)
|
||||
*offset_in_node = node->len - (len - offset);
|
||||
if (previous_node)
|
||||
*previous_node = previous;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
void dump_memory
|
||||
(
|
||||
const char * prefix,
|
||||
const void * data,
|
||||
uint32 len
|
||||
)
|
||||
{
|
||||
uint32 i,j;
|
||||
char text[96]; // only 3*16 + 16 max by line needed
|
||||
uint8 * byte;
|
||||
char * ptr;
|
||||
|
||||
byte = (uint8 *) data;
|
||||
|
||||
for ( i = 0; i < len; i += 16 )
|
||||
{
|
||||
ptr = text;
|
||||
|
||||
for ( j = i; j < i+16 ; j++ )
|
||||
{
|
||||
if ( j < len )
|
||||
sprintf(ptr, "%02x ",byte[j]);
|
||||
else
|
||||
sprintf(ptr, " ");
|
||||
ptr += 3;
|
||||
};
|
||||
|
||||
for (j = i; j < len && j < i+16;j++)
|
||||
{
|
||||
if ( byte[j] >= ' ' && byte[j] <= 0x7e )
|
||||
*ptr = byte[j];
|
||||
else
|
||||
*ptr = '.';
|
||||
|
||||
ptr++;
|
||||
};
|
||||
*ptr = '\n';
|
||||
ptr++;
|
||||
*ptr = '\0';
|
||||
|
||||
if (prefix)
|
||||
DPRINTF(prefix);
|
||||
DPRINTF(text);
|
||||
|
||||
// next line
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
void dump_data(net_data *data)
|
||||
{
|
||||
net_data_node * node;
|
||||
|
||||
if (! data)
|
||||
return;
|
||||
|
||||
DPRINTF("---- net_data %p: total len %ld\n", data, data->len);
|
||||
|
||||
DPRINTF("data_list:\n");
|
||||
node = data->data_list;
|
||||
while (node) {
|
||||
DPRINTF(" * node %p: data %p, len %ld\n", node, node->data, node->len);
|
||||
dump_memory(" ", node->data, node->len);
|
||||
DPRINTF(" next: %p\n", node->next_data);
|
||||
|
||||
node = node->next_data;
|
||||
};
|
||||
|
||||
DPRINTF("node_list:\n");
|
||||
node = data->node_list;
|
||||
while (node) {
|
||||
DPRINTF(" * node %p: data %p, len %ld, ref_count %ld\n", node, node->data, node->len, node->ref_count);
|
||||
if (node->free_func)
|
||||
DPRINTF(" free_func: %p, free_cookie %p\n", node->free_func, node->free_cookie);
|
||||
DPRINTF(" next: %p\n", node->next);
|
||||
|
||||
node = node->next;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// #pragma mark [data Purgatory functions]
|
||||
|
||||
// --------------------------------------------------
|
||||
static int32 datas_purgatory_thread(void *data)
|
||||
{
|
||||
while (true) {
|
||||
if (acquire_sem(g_datas_purgatory_sync) != B_OK)
|
||||
break;
|
||||
|
||||
// okay, time to cleanup some net_data(s)
|
||||
g_memory_pool->for_each_pool_node(g_datas_pool, data_death, NULL);
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
static status_t data_death(memory_pool * pool, void * node, void * cookie)
|
||||
{
|
||||
net_data *data;
|
||||
|
||||
data = (net_data *) node;
|
||||
if (data->flags & DATA_TO_FREE)
|
||||
delete_data(data, false);
|
||||
|
||||
return 0; // B_OK;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
static status_t data_queue_death(memory_pool * pool, void * node, void * cookie)
|
||||
{
|
||||
return delete_data_queue((net_data_queue *) node);
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
/* data.h
|
||||
* private definitions for network data chunks support
|
||||
*/
|
||||
|
||||
#ifndef OBOS_NET_STACK_DATA_H
|
||||
#define OBOS_NET_STACK_DATA_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern status_t start_data_service();
|
||||
extern status_t stop_data_service();
|
||||
|
||||
// Network data chunk(s)
|
||||
extern net_data * new_data(void);
|
||||
extern status_t delete_data(net_data *nd, bool interrupt_safe);
|
||||
|
||||
extern net_data * duplicate_data(net_data *from);
|
||||
extern net_data * clone_data(net_data *from);
|
||||
|
||||
extern status_t prepend_data(net_data *nd, const void *data, uint32 bytes, data_node_free_func freethis);
|
||||
extern status_t append_data(net_data *nd, const void *data, uint32 bytes, data_node_free_func freethis);
|
||||
extern status_t insert_data(net_data *nd, uint32 offset, const void *data, uint32 bytes, data_node_free_func freethis);
|
||||
extern status_t remove_data(net_data *nd, uint32 offset, uint32 bytes);
|
||||
|
||||
extern status_t add_data_free_node(net_data *nd, void *arg1, void *arg2, data_node_free_func freethis);
|
||||
|
||||
extern uint32 copy_from_data(net_data *nd, uint32 offset, void * copyinto, uint32 bytes);
|
||||
|
||||
extern void dump_data(net_data *data);
|
||||
|
||||
// Network data(s) queue(s)
|
||||
extern net_data_queue * new_data_queue(size_t max_bytes);
|
||||
extern status_t delete_data_queue(net_data_queue *queue);
|
||||
|
||||
extern status_t empty_data_queue(net_data_queue *queue);
|
||||
extern status_t enqueue_data(net_data_queue *queue, net_data *data);
|
||||
extern size_t dequeue_data(net_data_queue *queue, net_data **data, bigtime_t timeout, bool peek);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OBOS_NET_STACK_DATA_H
|
@ -12,7 +12,7 @@
|
||||
#include <OS.h>
|
||||
|
||||
#include "datalink.h"
|
||||
#include "data.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/* Defines we need */
|
||||
#define NETWORK_INTERFACES "network/interfaces"
|
||||
@ -233,19 +233,20 @@ status_t enable_interface(ifnet_t *iface, bool enable)
|
||||
status_t interface_reader(void *args)
|
||||
{
|
||||
ifnet_t *iface = args;
|
||||
net_data *nd;
|
||||
net_buffer *buffer;
|
||||
status_t status;
|
||||
|
||||
if (!iface || iface->module == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
while(iface->if_flags & IFF_UP) {
|
||||
status = iface->module->receive_data(iface, &nd);
|
||||
if (status < B_OK || nd == NULL)
|
||||
buffer = NULL;
|
||||
status = iface->module->receive_buffer(iface, &buffer);
|
||||
if (status < B_OK || buffer == NULL)
|
||||
continue;
|
||||
|
||||
dump_data(nd);
|
||||
delete_data(nd, false);
|
||||
dump_buffer(buffer);
|
||||
delete_buffer(buffer, false);
|
||||
};
|
||||
|
||||
return B_OK;
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "memory_pool.h"
|
||||
|
||||
#include "datalink.h"
|
||||
#include "data.h"
|
||||
#include "buffer.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* Defines we need */
|
||||
@ -36,7 +36,7 @@ static status_t start(void)
|
||||
|
||||
puts("stack: starting...");
|
||||
|
||||
start_data_service();
|
||||
start_buffers_service();
|
||||
start_timers_service();
|
||||
|
||||
start_datalink_layer();
|
||||
@ -54,7 +54,7 @@ static status_t stop(void)
|
||||
stop_datalink_layer();
|
||||
|
||||
stop_timers_service();
|
||||
stop_data_service();
|
||||
stop_buffers_service();
|
||||
|
||||
|
||||
puts("stack: stopped.");
|
||||
@ -79,36 +79,36 @@ struct net_stack_module_info nsmi = {
|
||||
register_interface,
|
||||
unregister_interface,
|
||||
|
||||
// net_data support
|
||||
new_data,
|
||||
delete_data,
|
||||
duplicate_data,
|
||||
clone_data,
|
||||
// net_buffer support
|
||||
new_buffer,
|
||||
delete_buffer,
|
||||
duplicate_buffer,
|
||||
clone_buffer,
|
||||
split_buffer,
|
||||
|
||||
prepend_data,
|
||||
append_data,
|
||||
insert_data,
|
||||
remove_data,
|
||||
add_to_buffer,
|
||||
remove_from_buffer,
|
||||
|
||||
add_data_free_node,
|
||||
attach_buffer_free_element,
|
||||
|
||||
copy_from_data,
|
||||
read_buffer,
|
||||
write_buffer,
|
||||
|
||||
dump_data,
|
||||
dump_buffer,
|
||||
|
||||
// net_data_queue support
|
||||
new_data_queue,
|
||||
delete_data_queue,
|
||||
empty_data_queue,
|
||||
enqueue_data,
|
||||
dequeue_data,
|
||||
// net_buffer_queue support
|
||||
new_buffer_queue,
|
||||
delete_buffer_queue,
|
||||
empty_buffer_queue,
|
||||
enqueue_buffer,
|
||||
dequeue_buffer,
|
||||
|
||||
// Timers support
|
||||
new_net_timer,
|
||||
delete_net_timer,
|
||||
start_net_timer,
|
||||
cancel_net_timer,
|
||||
get_net_timer_appointment
|
||||
net_timer_appointment
|
||||
};
|
||||
|
||||
status_t std_ops(int32 op, ...)
|
||||
|
Binary file not shown.
@ -57,7 +57,7 @@ status_t start_timers_service()
|
||||
set_sem_owner(g_timers.wait, B_SYSTEM_TEAM);
|
||||
#endif
|
||||
|
||||
g_timers_thread = spawn_kernel_thread(timers_thread, "net timers runner", B_URGENT_DISPLAY_PRIORITY, &g_timers);
|
||||
g_timers_thread = spawn_kernel_thread(timers_thread, "net timers lone runner", B_URGENT_DISPLAY_PRIORITY, &g_timers);
|
||||
if (g_timers_thread < B_OK)
|
||||
return g_timers_thread;
|
||||
|
||||
@ -128,7 +128,7 @@ status_t cancel_net_timer(net_timer *nt)
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t get_net_timer_appointment(net_timer *nt, bigtime_t *period, bigtime_t *when)
|
||||
status_t net_timer_appointment(net_timer *nt, bigtime_t *period, bigtime_t *when)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ extern net_timer * new_net_timer(void);
|
||||
extern status_t delete_net_timer(net_timer *nt);
|
||||
extern status_t start_net_timer(net_timer *nt, net_timer_func hook, void *cookie, bigtime_t period);
|
||||
extern status_t cancel_net_timer(net_timer *nt);
|
||||
extern status_t get_net_timer_appointment(net_timer *nt, bigtime_t *period, bigtime_t *when);
|
||||
extern status_t net_timer_appointment(net_timer *nt, bigtime_t *period, bigtime_t *when);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user