1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
/*
* Pure Data Packet system implementation: Packet Manager Interface
* 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.
*
*/
/*
This file contains the pdp packet manager interface specification.
It is an implementation of the "Object Pool" pattern with lazy instantiation
and lazy destruction.
The pool is a growable array. It can only grow larger. Packets are represented
by an integer, which is an index in this array.
The standard "pure" packets (the ones which use a flat memory buffer) have recovery
for resource depletion (main memory). If an out of memory condition is met
on allocation of a new package, the garbage collector kicks in and frees unused
packets until the out of memory condition is solved. Since an out of memory
condition can be fatal for other parts of the program, pdp also supports a
memory limit, to ensure some kind of safety margin.
The "not so pure" packets should resolve resource conflicts in their own factory method,
since the constructor is responsible for allocating external resources. The standard
way to do this is to allocate a packet, free it's resources and allocate a new packet
until the resource allocation succeeds. Especially for these kinds of packets, the
pdp pool supports an explicit reuse method. This returns a valid packet if it can reuse
one (based on the high level type description).
Packets that don't have memory managing methods defined in the packet class
(Standard packets) are treated as a header concatenated with a flat memory buffer, and
can be copied and cloned without problems. So, if a packet contains pointers to other
data or code, it can't be a pure packet.
The interface to the packet manager contains the following managing methods:
* pdp_packet_new: create a new packet or reuse a previous one
* pdp_packet_mark_passing: conditionally release a packet (for passing to other objects)
* pdp_packet_unmark_passing: turn a conditionally released packet back to normal (i.e. before deletion)
* pdp_packet_mark_unused: release a packet
* pdp_packet_copy_ro: register a packet for read only use
* pdp_packet_copy_rw: register a packet for read/write use (this creates a copy if necessary)
* pdp_packet_clone_rw: create a new packet using a template, but don't copy the data
And two methods for raw data access
* pdp_packet_header: retreive the header of the packet
* pdp_packet_data: retreive the data buffer of the packet (only for static packets)
All the methods declared in this header are supposed to be thread safe, so you
can call them from the pd and pdp thread.
*/
#ifndef PDP_PACKET_H
#define PDP_PACKET_H
/* all symbols are C-style */
#ifdef __cplusplus
extern "C"
{
#endif
//typedef int (*t_pdp_attribute_method)(struct _pdp_list *);
typedef int (*t_pdp_factory_method)(t_pdp_symbol *);
#if 0
/* packet class attribute (method) */
typedef struct _pdp_attribute
{
t_pdp_symbol *name;
t_pdp_attribute_method method;
/* problem: do we support argument type checking ??
this seems to be better solved in a "spec doc" or a central place
where "reserved" methods can be defined. */
/* if null this means the input or output list can be anything */
struct _pdp_list *in_spec; // template for the input list (including default arguments)
struct _pdp_list *out_spec; // template for the output list
} t_pdp_attribute;
#endif
/* packet class header */
typedef struct _pdp_class
{
/* packet manips: non-pure data packets (using external resources) must define these */
t_pdp_packet_method1 reinit; /* reuse method for pdp_packet_new() */
t_pdp_packet_method2 clone; /* init from template for pdp_packet_clone_rw() */
t_pdp_packet_method2 copy; /* init & copy from template for pdp_packet_copy_rw() */
t_pdp_packet_method1 cleanup; /* free packet's resources (to be used by the garbage collector) */
t_pdp_symbol *type; /* type template for packet class */
t_pdp_factory_method create; /* the constructor */
//struct _pdp_list *attributes; /* list of attributes (packet methods) */
}t_pdp_class;
/* packet object header */
struct _pdp
{
/* meta info */
unsigned int type; /* main datatype of this object */
t_pdp_symbol *desc; /* high level type description (sort of a mime type) */
unsigned int size; /* datasize including header */
unsigned int flags; /* packet flags */
/* reference count */
unsigned int users; /* nb users of this object, readonly if > 1 */
unsigned int *refloc; /* location of reference to packet for passing packets */
/* class object */
t_pdp_class *theclass; /* if zero, the packet is a pure packet (just data, no member functions) */
u32 pad[9]; /* reserved to provide binary compatibility for future extensions */
union /* each packet type has a unique subheader */
{
t_raw raw; /* raw subheader (for extensions unkown to pdp core system) */
t_image image; /* (nonstandard internal) 16 bit signed planar bitmap image format */
t_bitmap bitmap; /* (standard) bitmap image (fourcc coded) */
//t_ca ca; /* cellular automaton state data */
//t_ascii ascii; /* ascii packet */
} info;
};
/* pdp data packet type id */
#define PDP_IMAGE 1 /* 16bit signed planar scanline encoded image packet */
//RESERVED: #define PDP_CA 2 /* 1bit toroidial shifted scanline encoded cellular automaton */
//RESERVED: #define PDP_ASCII 3 /* ascii packet */
//RESERVED: #define PDP_TEXTURE 4 /* opengl texture object */
//RESERVED: #define PDP_3DCONTEXT 5 /* opengl render context */
#define PDP_BITMAP 6 /* 8bit image packet (fourcc coded??) */
//RESERVED: #define PDP_MATRIX 7 /* floating point/double matrix/vector packet (from gsl) */
/* PACKET FLAGS */
#define PDP_FLAG_DONOTCOPY (1<<0) /* don't copy the packet on register_rw, instead return an invalid packet */
/* class methods */
t_pdp_class *pdp_class_new(t_pdp_symbol *type, t_pdp_factory_method create);
#if 0
void pdp_class_addmethod(t_pdp_class *c, t_pdp_symbol *name, t_pdp_attribute_method method,
struct _pdp_list *in_spec, struct _pdp_list *out_spec);
#endif
/* packet factory method + registration */
int pdp_factory_newpacket(t_pdp_symbol *type);
#if 0
/* send a message to a packet (packet polymorphy)
this returns NULL on failure, or a return list
the return list should be freed by the caller */
int pdp_packet_op(t_pdp_symbol *operation, struct _pdp_list *stack);
#endif
/* debug */
void pdp_packet_print_debug(int packet);
/* hard coded packet methods */
int pdp_packet_copy_ro(int handle); /* get a read only copy */
int pdp_packet_copy_rw(int handle); /* get a read/write copy */
int pdp_packet_clone_rw(int handle); /* get an empty read/write packet of the same type (only copy header) */
void pdp_packet_mark_unused(int handle); /* indicate that you're done with the packet */
void pdp_packet_mark_passing(int *phandle); /* mark a packet as passing */
void pdp_packet_unmark_passing(int packet); /* unmark a packet as passing (i.e. before marking unused) */
void pdp_packet_delete(int packet); /* like mark_unused, but really delete when refcount == 0 */
t_pdp* pdp_packet_header(int handle); /* get packet header */
void* pdp_packet_subheader(int handle); /* get packet subheader */
void* pdp_packet_data(int handle); /* get packet raw data */
int pdp_packet_compat(int packet0, int packet1);
int pdp_packet_reuse(t_pdp_symbol *description);
int pdp_packet_brandnew(unsigned int datatype, unsigned int datasize); /* create a new packet, don't reuse */
int pdp_packet_writable(int packet); /* returns true if packet is writable */
void pdp_packet_replace_with_writable(int *packet); /* replaces a packet with a writable copy */
void pdp_packet_mark_unused_atomic(int *handle); /* mark unused + set reference to -1 (for thread synchro) */
/* pool stuff */
int pdp_pool_collect_garbage(void); /* free all unused packets */
void pdp_pool_set_max_mem_usage(int max); /* set max mem usage */
/* a wrapper around malloc and free to keep track of pdp's memory usage */
void *pdp_alloc(int size);
void pdp_dealloc(void *stuff);
#ifdef __cplusplus
}
#endif
#endif
|