aboutsummaryrefslogtreecommitdiff
path: root/system/kernel/pdp_packet.c
diff options
context:
space:
mode:
authorPablo Martín <caedesv@users.sourceforge.net>2003-09-07 21:39:37 +0000
committerPablo Martín <caedesv@users.sourceforge.net>2003-09-07 21:39:37 +0000
commit599a8e20c02fa48bab5102d15fab79dd6b631c95 (patch)
tree80e8760e6a8fdc7d9144370dc569b38232b2b315 /system/kernel/pdp_packet.c
parentb509942daafa671a5b5ede267b6e786619ce8173 (diff)
Updating to last version of pdp 0.12.2
svn path=/trunk/externals/pdp/; revision=940
Diffstat (limited to 'system/kernel/pdp_packet.c')
-rw-r--r--system/kernel/pdp_packet.c957
1 files changed, 957 insertions, 0 deletions
diff --git a/system/kernel/pdp_packet.c b/system/kernel/pdp_packet.c
new file mode 100644
index 0000000..a811381
--- /dev/null
+++ b/system/kernel/pdp_packet.c
@@ -0,0 +1,957 @@
+/*
+ * Pure Data Packet system implementation: Packet Manager
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include "pdp.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+
+
+/* TODO:
+ implement an indexing system to the packet pool (array) to speed up searches.
+ -> a list of lists of recycled packes, arranged by packet type.
+ -> a list of unused slots
+*/
+
+
+
+#define D if (0)
+
+/* all symbols are C style */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/* pdp specific constants */
+#define PDP_ALIGN 8
+
+/* this needs to be able to grow dynamically, think about it later */
+/* for ordinary work, this is enough and can help finding memory leaks */
+
+#define PDP_INITIAL_POOL_SIZE 1
+#define PDP_PACKET_MAX_MEM_USAGE -1
+
+/* the pool */
+static unsigned int pdp_packet_mem_usage;
+static unsigned int pdp_packet_max_mem_usage;
+static int pdp_pool_size;
+static t_pdp** pdp_pool;
+
+/* this is for detecting memory leaks */
+static int pdp_packet_count;
+
+/* some global vars */
+static t_symbol* pdp_sym_register_rw;
+static t_symbol* pdp_sym_register_ro;
+static t_symbol* pdp_sym_process;
+
+/* mutex */
+static pthread_mutex_t pdp_pool_mutex;
+
+/* the list of classes */
+static t_pdp_list *class_list;
+
+/* debug */
+void
+pdp_packet_print_debug(int packet)
+{
+ t_pdp *h = pdp_packet_header(packet);
+ post("debug info for packet %d", packet);
+ if (!h){
+ post("invalid packet");
+ }
+ else{
+ post ("\ttype: %d", h->type);
+ post ("\tdesc: %s", h->desc ? h->desc->s_name : "unknown");
+ post ("\tsize: %d", h->size);
+ post ("\tflags: %x", h->flags);
+ post ("\tusers: %d", h->users);
+ post ("\trefloc: %x", h->refloc);
+ post ("\tclass: %x", h->theclass);
+ }
+}
+
+
+
+/* setup methods */
+
+void
+pdp_packet_setup(void)
+{
+
+ pdp_pool_size = PDP_INITIAL_POOL_SIZE;
+ pdp_packet_count = 0;
+ pdp_packet_mem_usage = 0;
+ pdp_packet_max_mem_usage = PDP_PACKET_MAX_MEM_USAGE;
+ pdp_pool = (t_pdp **)malloc(PDP_INITIAL_POOL_SIZE * sizeof(t_pdp *));
+ bzero(pdp_pool, pdp_pool_size * sizeof(t_pdp *));
+ pdp_sym_register_rw = gensym("register_rw");
+ pdp_sym_register_ro = gensym("register_ro");
+ pdp_sym_process = gensym("process");
+ pdp_packet_count = 0;
+ class_list = pdp_list_new(0);
+
+ pthread_mutex_init(&pdp_pool_mutex, NULL);
+}
+
+/* class methods */
+t_pdp_class *pdp_class_new(t_pdp_symbol *type, t_pdp_factory_method create){
+ t_pdp_class *c = (t_pdp_class *)pdp_alloc(sizeof(t_pdp_class));
+ memset(c, 0, sizeof(t_pdp_class));
+ c->create = create;
+ c->type = type; // set type
+ //c->attributes = pdp_list_new(0); // create an empty attribute list
+ pdp_list_add(class_list, a_pointer, (t_pdp_word)((void *)c));
+ //post("added class %s %x", c->type->s_name, c->create);
+
+ return c;
+}
+
+#if 0
+void pdp_class_addmethod(t_pdp_class *c, t_pdp_symbol *name, t_pdp_attribute_method method,
+ t_pdp_list *in_spec, t_pdp_list *out_spec)
+{
+ t_pdp_attribute *attr = (t_pdp_attribute *)pdp_alloc(sizeof(t_pdp_attribute));
+ attr->name = name;
+ attr->method = method;
+ attr->in_spec = in_spec;
+ attr->out_spec = out_spec;
+ pdp_list_add_pointer(c->attributes, attr);
+
+}
+#endif
+
+/* the packet factory */
+int pdp_factory_newpacket(t_pdp_symbol *type)
+{
+ t_pdp_class *c;
+ t_pdp_atom *a = class_list->first;
+ while(a){
+ c = (t_pdp_class *)(a->w.w_pointer);
+ if (c->type && pdp_type_description_match(type, c->type)){
+ //post("method %x, type %s", c->create, type->s_name);
+ return (c->create) ? (*c->create)(type) : -1;
+ }
+ a = a->next;
+ }
+ return -1;
+}
+
+#if 0
+/* generic methods. actually a forth word operation on a stack.
+ first item on stack must be a packet and it's type will
+ determine the place to look for the operator */
+int pdp_packet_op(t_pdp_symbol *operation, struct _pdp_list *stack)
+{
+ int packet = stack->first->w.w_packet;
+ t_pdp *h = pdp_packet_header(packet);
+ t_pdp_atom *i;
+ t_pdp_attribute *attr;
+
+ if (!(h && h->theclass)) goto exit;
+
+ PDP_POINTER_IN(h->theclass->attributes, i, attr){
+ //post("attribute:%s", attr->name->s_name);
+ if (attr->name == operation){
+
+ /* FOUND -> exec (check arguments first ???) */
+ return attr->method (stack);
+ }
+
+ }
+ exit:
+ // method not found
+ post ("WARNING: pdp_packet_op: packet %d from class %s has no operation %s",
+ packet, (h && h->theclass) ? h->theclass->type->s_name : "UNKNOWN", operation->s_name);
+ return 0;
+}
+
+#endif
+
+static void
+_pdp_pool_expand(void){
+ int i;
+
+ /* double the size */
+ int new_pool_size = pdp_pool_size << 1;
+ t_pdp **new_pool = (t_pdp **)malloc(new_pool_size * sizeof(t_pdp *));
+ bzero(new_pool, new_pool_size * sizeof(t_pdp *));
+ memcpy(new_pool, pdp_pool, pdp_pool_size * sizeof(t_pdp *));
+ free(pdp_pool);
+ pdp_pool = new_pool;
+ pdp_pool_size = new_pool_size;
+
+ D post("DEBUG: _pdp_pool_expand: resized pool to contain %d packets", pdp_pool_size);
+}
+
+
+
+
+/* private _pdp_packet methods */
+
+/* packets can only be created and destroyed using these 2 methods */
+/* it updates the mem usage and total packet count */
+
+static void
+_pdp_packet_dealloc(t_pdp *p)
+{
+ unsigned int size = p->size;
+ if (p->theclass && p->theclass->cleanup)
+ (*p->theclass->cleanup)(p);
+
+ free (p);
+ pdp_packet_mem_usage -= size;
+ pdp_packet_count--;
+ D post("DEBUG: _pdp_packet_new_dealloc: freed packet. pool contains %d packets", pdp_packet_count);
+}
+
+static t_pdp*
+_pdp_packet_alloc(unsigned int datatype, unsigned int datasize)
+{
+ unsigned int totalsize = datasize + PDP_HEADER_SIZE;
+ unsigned int align;
+ t_pdp *p = 0;
+
+ /* check if there is a memory usage limit */
+ if (pdp_packet_max_mem_usage){
+ /* if it would exceed the limit, fail */
+ if (pdp_packet_mem_usage + totalsize > pdp_packet_max_mem_usage){
+ D post("DEBUG: _pdp_packet_new_alloc: memory usage limit exceeded");
+ return 0;
+ }
+ }
+ p = (t_pdp *)malloc(totalsize);
+ if (p){
+ align = ((unsigned int)p) & (PDP_ALIGN - 1);
+ if (align) post("WARNING: _pdp_packet_alloc: data misaligned by %x", align);
+ memset(p, 0, PDP_HEADER_SIZE); //initialize header to 0
+ p->type = datatype;
+ p->size = totalsize;
+ p->users = 1;
+ pdp_packet_mem_usage += totalsize;
+ pdp_packet_count++;
+ D post("DEBUG: _pdp_packet_new_alloc: allocated new packet. pool contains %d packets, using %d bytes",
+ pdp_packet_count, pdp_packet_mem_usage);
+ }
+
+ return p;
+}
+
+
+void
+pdp_packet_destroy(void)
+{
+ int i = 0;
+ /* dealloc all the data in object stack */
+ post("DEBUG: pdp_packet_destroy: clearing object pool.");
+ while ((i < pdp_pool_size) && (pdp_pool[i])) _pdp_packet_dealloc(pdp_pool[i++]);
+}
+
+
+
+/* try to find a packet based on main type and datasize */
+static int
+_pdp_packet_reuse_type_size(unsigned int datatype, unsigned int datasize)
+{
+ unsigned int totalsize = datasize + PDP_HEADER_SIZE;
+ int i = 0;
+ int return_packet = -1;
+ t_pdp* p;
+
+ for (i=0; i < pdp_pool_size; i++){
+ p = pdp_pool[i];
+ /* check if we can reuse this one if it is already allocated */
+ if (p) {
+ /* search for unused packets of equal size & type */
+ if ((p->users == 0) && (p->size == totalsize) && (p->type == datatype)){
+ D post("DEBUG: _pdp_packet_reuse_type_size: can reuse %d", i);
+
+ /* if possible, a packet will be reused and reinitialized
+ i haven't found a use for this, so it's only used for discriminating
+ between pure and not-so-pure packets */
+ if (p->theclass && p->theclass->reinit){
+ (*p->theclass->reinit)(p);
+ }
+ /* if no re-init method is found, the header will be reset to all 0
+ this ensures the header is in a predictable state */
+ else {
+ memset(p, 0, PDP_HEADER_SIZE);
+ p->type = datatype;
+ p->size = totalsize;
+ }
+
+ p->users = 1;
+ return_packet = i;
+ goto exit;
+ }
+ else{
+ D post("DEBUG _pdp_packet_reuse_type_size: can't reuse %d, (%d users)", i, p->users);
+ }
+ }
+ }
+
+ D post("DEBUG: _pdp_packet_reuse_type_size: no reusable packet found");
+
+ exit:
+ return return_packet;
+}
+
+
+/* create a new packet in an empty slot.
+ if this fails, the garbage collector needs to be called */
+static int
+_pdp_packet_create_in_empty_slot(unsigned int datatype, unsigned int datasize /*without header*/)
+{
+ unsigned int totalsize = datasize + PDP_HEADER_SIZE;
+ int i = 0;
+ int return_packet = -1;
+ int out_of_mem = 0;
+ t_pdp* p;
+
+
+ /* no reusable packets found, try to find an empty slot */
+ for (i=0; i < pdp_pool_size; i++){
+ p = pdp_pool[i];
+ if (!p) {
+ p = _pdp_packet_alloc(datatype, datasize);
+
+ if (!p) {
+ D post("DEBUG: _pdp_packet_create_in_empty_slot: out of memory (malloc returned NULL)");
+ return_packet = -1;
+ goto exit;
+ }
+
+ pdp_pool[i] = p;
+ return_packet = i;
+ goto exit;
+ }
+ }
+
+ /* if we got here the pool is full: resize the pool and try again */
+ _pdp_pool_expand();
+ return_packet = _pdp_packet_create_in_empty_slot(datatype, datasize);
+
+ exit:
+ return return_packet;
+
+}
+
+/* find an unused packet, free it and create a new packet.
+ if this fails, something is seriously wrong */
+static int
+_pdp_packet_create_in_unused_slot(unsigned int datatype, unsigned int datasize /*without header*/)
+{
+ unsigned int totalsize = datasize + PDP_HEADER_SIZE;
+ int i = 0;
+ int return_packet = -1;
+ int out_of_mem = 0;
+ t_pdp* p;
+
+ D post("DEBUG: _pdp_packet_create_in_unused_slot: collecting garbage");
+
+ /* search backwards */
+ for (i=pdp_pool_size-1; i >= 0; i--){
+ p = pdp_pool[i];
+ if (p){
+ if (p->users == 0){
+ _pdp_packet_dealloc(p);
+ p = _pdp_packet_alloc(datatype, datasize);
+ pdp_pool[i] = p;
+
+ /* alloc succeeded, return */
+ if (p) {
+ post("DEBUG _pdp_packet_create_in_unused_slot: garbage collect succesful");
+ return_packet = i;
+ goto exit;
+ }
+
+ /* alloc failed, continue collecting garbage */
+ D post("DEBUG _pdp_packet_create_in_unused_slot: freed one packet, still out of memory (malloc returned NULL)");
+ out_of_mem = 1;
+
+ }
+ }
+ }
+
+ /* if we got here, we ran out of memory */
+ D post("DEBUG: _pdp_packet_create_in_unused_slot: out of memory after collecting garbage");
+ return_packet = -1;
+
+exit:
+ return return_packet;
+}
+
+/* warning: for "not so pure" packets, this method will only return an initialized
+ packet if it can reuse a privious one. that is, if it finds a reinit method
+ in the packet. use the pdp_packet_new_<type> constructor if possible */
+
+static int
+_pdp_packet_brandnew(unsigned int datatype, unsigned int datasize /*without header*/)
+{
+ int return_packet = -1;
+
+ /* try to create a new packet in an empty slot */
+ return_packet = _pdp_packet_create_in_empty_slot(datatype, datasize);
+ if (return_packet != -1) goto exit;
+
+ /* if we still don't have a packet, we need to call the garbage collector until we can allocate */
+ return_packet = _pdp_packet_create_in_unused_slot(datatype, datasize);
+
+ exit:
+ return return_packet;
+}
+
+
+static int
+_pdp_packet_new(unsigned int datatype, unsigned int datasize /*without header*/)
+{
+ int return_packet = -1;
+
+ /* try to reuse a packet based on main type and datasize */
+ return_packet = _pdp_packet_reuse_type_size(datatype, datasize);
+ if (return_packet != -1) goto exit;
+
+ /* create a brandnew packet */
+ return_packet = _pdp_packet_brandnew(datatype, datasize);
+ if (return_packet != -1) goto exit;
+
+ post("WARNING: maximum packet memory usage limit (%d bytes) reached after garbage collect.", pdp_packet_max_mem_usage);
+ post("WARNING: increase memory limit or decrease packet usage (i.e. pdp_loop, pdp_delay).");
+ post("WARNING: pool contains %d packets, using %d bytes.", pdp_packet_count, pdp_packet_mem_usage);
+
+ exit:
+ return return_packet;
+
+}
+
+
+
+/* public pool operations: have to be thread safe so each entry point
+ locks the mutex */
+
+/* reuse an old packet based on high level description */
+int
+pdp_packet_reuse(t_pdp_symbol *description)
+{
+ int i;
+ int return_packet = -1;
+ t_pdp *p;
+
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ for (i=0; i < pdp_pool_size; i++){
+ p = pdp_pool[i];
+ /* check if we can reuse this one if it is already allocated */
+ if ((p) && (p->users == 0) && (p->desc == description)){
+ /* mark it as used */
+ p->users = 1;
+ return_packet = i;
+ goto gotit;
+ }
+ }
+
+ gotit:
+ /* LOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+
+ return return_packet;
+
+
+}
+
+/* create a new packet, or reuse an old one based on main type and size */
+int
+pdp_packet_new(unsigned int datatype, unsigned int datasize /*without header*/)
+{
+ int packet;
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ packet = _pdp_packet_new(datatype, datasize);
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+ return packet;
+}
+
+
+/* create a brand new packet, don't reuse an old one */
+int
+pdp_packet_brandnew(unsigned int datatype, unsigned int datasize /*without header*/)
+{
+ int packet;
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ packet = _pdp_packet_brandnew(datatype, datasize);
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+ return packet;
+}
+
+
+/* this returns a copy of a packet for read only access. */
+int
+pdp_packet_copy_ro(int handle)
+{
+ int out_handle = -1;
+ t_pdp* p;
+
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ if ((handle >= 0)
+ && (handle < pdp_pool_size)
+ && (p = pdp_pool[handle])){
+
+ /* it is an error to copy a packet without an owner */
+ if (!p->users){
+ post("pdp_packet_copy_ro: ERROR: request to copy packet %d which has 0 users", handle);
+ out_handle = -1;
+ }
+
+ /* if it's a passing packet, reset the reference location
+ and turn it into a normal packet */
+ else if (p->refloc){
+ *p->refloc = -1;
+ p->refloc = 0;
+ out_handle = handle;
+ }
+ /* if it's a normal packet, increase the number of users */
+ else {
+ p->users++;
+ out_handle = handle;
+ }
+ }
+ else out_handle = -1;
+
+ //post("pdp_copy_ro: outhandle:%d", out_handle);
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+
+ return out_handle;
+}
+
+/* copy a packet. if the packet is marked passing, it will be aquired.
+ otherwize a new packet will be created with a copy of the contents. */
+
+int
+pdp_packet_copy_rw(int handle)
+{
+ int out_handle = -1;
+ t_pdp* p;
+
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ if ((handle >= 0)
+ && (handle < pdp_pool_size)
+ && (p = pdp_pool[handle])){
+ /* if there are other users, copy the object otherwize return the same handle */
+
+ /* it is an error to copy a packet without an owner */
+ if (!p->users){
+ post("pdp_packet_copy_rw: ERROR: request to copy packet %d which has 0 users", handle);
+ out_handle = -1;
+ }
+
+ /* if it is a passing packet, remove the owner's reference to it */
+ else if (p->refloc){
+ *p->refloc = -1;
+ p->refloc = 0;
+ out_handle = handle;
+ }
+
+ /* check if packet supports copy (for fanout) */
+ else if(p->flags & PDP_FLAG_DONOTCOPY) out_handle = -1;
+
+
+ /* copy the packet, since it already has 1 or more users */
+ else{
+ int new_handle = _pdp_packet_new(p->type, p->size - PDP_HEADER_SIZE);
+ t_pdp* new_p = pdp_packet_header(new_handle);
+
+ /* check if valid */
+ if (!new_p) out_handle = -1;
+
+ else {
+ /* if a copy constructor is found, it will be called */
+ if (p->theclass && p->theclass->copy){
+ (*p->theclass->copy)(new_p, p);
+ }
+ /* if not, the entire packet will be copied, assuming a pure data packet */
+ else {
+ memcpy(new_p, p, p->size);
+ }
+ new_p->users = 1;
+ out_handle = new_handle;
+ }
+ }
+
+ //post("pdp_copy_rw: inhandle:%d outhandle:%d", handle, out_handle);
+
+ }
+ else out_handle = -1;
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+ return out_handle;
+}
+
+/* create a new packet, copying the header data of another
+ packet, without copying the data */
+int
+pdp_packet_clone_rw(int handle)
+{
+ int out_handle;
+ t_pdp* p;
+
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ if ((handle >= 0)
+ && (handle < pdp_pool_size)
+ && (p = pdp_pool[handle])){
+
+ /* clone the packet header, don't copy the data */
+ int new_handle = _pdp_packet_new(p->type, p->size - PDP_HEADER_SIZE);
+ t_pdp* new_p = pdp_packet_header(new_handle);
+
+ /* if a clone initializer is found, it will be called */
+ if (p->theclass && p->theclass->clone){
+ (*p->theclass->clone)(new_p, p);
+ }
+ /* if not, just the header will be copied, assuming a pure data packet */
+ else {
+ memcpy(new_p, p, PDP_HEADER_SIZE);
+ }
+ new_p->users = 1; /* the new packet has 1 user */
+ new_p->refloc = 0; /* it is not a passing packet, even if the template was */
+ out_handle = new_handle;
+ }
+
+ else out_handle = -1;
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+
+ return out_handle;
+}
+
+void
+_pdp_packet_mark_unused_nolock(int handle)
+{
+ t_pdp* p;
+
+ if ((handle >= 0) && (handle < pdp_pool_size)){
+ if (p = pdp_pool[handle]) {
+ /* mark_unused on a passing packet has no effect
+ this is to support automatic conversion for passing packets
+ so in order to delete a passing packet, it should be marked normal first */
+ if (p->refloc){
+ post("DEBUG: pdp_mark_unused called on a passing packet. ignored.");
+ return;
+ }
+
+ /* decrease the refcount */
+ if (p->users) {
+ p->users--;
+ //post("pdp_mark_unused: handle %d, users left %d", handle, p->users);
+ }
+ else {
+ post("pdp_mark_unused: ERROR: handle %d has zero users (duplicate pdp_mark_unused ?)", handle);
+ }
+ }
+ else {
+ post("pdp_mark_unused: ERROR: invalid handle %d: no associated object", handle);
+ }
+ }
+
+ else {
+ /* -1 is the only invalid handle that doesn't trigger a warning */
+ if (handle != -1) post("pdp_mark_unused: WARNING: invalid handle %d: out of bound", handle);
+ }
+
+}
+
+/* mark a packet as unused, decreasing the reference count.
+ if the reference count reaches zero, the packet is ready to be recycled
+ by a new packet allocation. it is illegal to reference a packet with
+ reference count == zero. if the reference count is not == 1, only readonly
+ access is permitted. */
+
+void
+pdp_packet_mark_unused(int handle)
+{
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ _pdp_packet_mark_unused_nolock(handle);
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+}
+
+void
+pdp_packet_mark_unused_atomic(int *handle)
+{
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ _pdp_packet_mark_unused_nolock(*handle);
+ *handle = -1;
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+}
+
+/* delete a packet. this is more than mark_unused:
+ it actually removes any reference. can be used for
+ some packet types that have "expensive" resources.
+ usually this is up to the garbage collector to call. */
+
+void
+pdp_packet_delete(int handle)
+{
+ t_pdp *header = pdp_packet_header(handle);
+
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+
+ /* check if it's a valid handle */
+ if ((handle >= 0) && (handle < pdp_pool_size) && pdp_pool[handle]){
+
+ /* mark it unused */
+ _pdp_packet_mark_unused_nolock(handle);
+
+ /* if no users, dealloc */
+ if (!header->users){
+ _pdp_packet_dealloc(header);
+ pdp_pool[handle] = NULL;
+ }
+
+ /* print a warning if failed */
+ else{
+ post("WARNING: pdp_packet_delete: packet %d was not deleted. %d users remaining",
+ handle, header->users);
+ }
+ }
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+
+}
+
+
+/* this turns any packet into a normal (non-passing) packet */
+
+void
+pdp_packet_unmark_passing(int packet)
+{
+ t_pdp* header = pdp_packet_header(packet);
+ if (!header) return;
+
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ header->refloc = 0;
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+
+}
+
+
+/* this marks a packet as passing. this means it changes
+ owner on first copy_ro or copy_rw. the previous owner is
+ notified by setting the handler to -1. */
+
+void
+pdp_packet_mark_passing(int *phandle)
+{
+ t_pdp* header = pdp_packet_header(*phandle);
+
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ if (header){
+ if (header->refloc){
+ post("pdp_packet_mark_passing: ERROR: duplicate mark_passing on packet %d", *phandle);
+ }
+ else if (1 != header->users){
+ post("pdp_packet_mark_passing: ERROR: packet %d is not exclusively owned by caller, it has %d users", *phandle, header->users);
+ }
+ else {
+ header->refloc = phandle;
+ }
+ }
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+
+}
+
+
+/* public data access methods */
+
+t_pdp*
+pdp_packet_header(int handle)
+{
+ if ((handle >= 0) && (handle < pdp_pool_size)) return pdp_pool[handle];
+ else return 0;
+}
+
+void*
+pdp_packet_subheader(int handle)
+{
+ t_pdp* header = pdp_packet_header(handle);
+ if (!header) return 0;
+ return (void *)(&header->info.raw);
+}
+
+void*
+pdp_packet_data(int handle)
+{
+ t_pdp *h;
+ if ((handle >= 0) && (handle < pdp_pool_size))
+ {
+ h = pdp_pool[handle];
+ if (!h) return 0;
+ return (char *)(h) + PDP_HEADER_SIZE;
+ }
+ else return 0;
+}
+
+
+/* OBSOLETE: use packet description */
+/* check if two packets are allocated and of the same type */
+bool pdp_packet_compat(int packet0, int packet1)
+{
+
+ t_pdp *header0 = pdp_packet_header(packet0);
+ t_pdp *header1 = pdp_packet_header(packet1);
+
+ if (!(header1)){
+ //post("pdp_type_compat: invalid header packet1");
+ return 0;
+ }
+ if (!(header0)){
+ //post("pdp_type_compat: invalid header packet 0");
+ return 0;
+ }
+ if (header0->type != header1->type){
+ //post("pdp_type_compat: types do not match");
+ return 0;
+ }
+
+ return 1;
+}
+
+int pdp_packet_writable(int packet) /* returns true if packet is writable */
+{
+ t_pdp *h = pdp_packet_header(packet);
+ if (!h) return 0;
+ return (h->users == 1);
+}
+
+void pdp_packet_replace_with_writable(int *packet) /* replaces a packet with a writable copy */
+{
+ int new_p;
+ if (!pdp_packet_writable(*packet)){
+ new_p = pdp_packet_copy_rw(*packet);
+ pdp_packet_mark_unused(*packet);
+ *packet = new_p;
+ }
+
+}
+
+/* pool stuff */
+
+int
+pdp_pool_collect_garbage(void)
+{
+ t_pdp *p;
+ int i;
+ int nbpackets = pdp_packet_count;
+
+ /* LOCK */
+ pthread_mutex_lock(&pdp_pool_mutex);
+
+ for (i=0; i < pdp_pool_size; i++){
+ p = pdp_pool[i];
+ if(p && !p->users) {
+ _pdp_packet_dealloc(p);
+ pdp_pool[i] = 0;
+ }
+ }
+ nbpackets -= pdp_packet_count;
+ //post("pdp_pool_collect_garbage: deleted %d unused packets", nbpackets);
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&pdp_pool_mutex);
+
+ return nbpackets;
+}
+
+void
+pdp_pool_set_max_mem_usage(int max)
+{
+ if (max < 0) max = 0;
+ pdp_packet_max_mem_usage = max;
+
+}
+
+
+
+
+
+
+/* malloc wrapper that calls garbage collector */
+void *pdp_alloc(int size)
+{
+ void *ptr = malloc(size);
+
+ //post ("malloc called for %d bytes", size);
+
+ if (ptr) return ptr;
+
+ post ("malloc failed in a pdp module: running garbage collector.");
+
+ pdp_pool_collect_garbage();
+ return malloc(size);
+}
+
+
+void pdp_dealloc(void *stuff)
+{
+ free (stuff);
+}
+
+#ifdef __cplusplus
+}
+#endif