~kamalmostafa/ubuntu/lucid/pdp/fix-504941-ftbfs

« back to all changes in this revision

Viewing changes to system/kernel/pdp_packet.c

  • Committer: Bazaar Package Importer
  • Author(s): Guenter Geiger (Debian/GNU)
  • Date: 2005-03-15 22:21:05 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050315222105-1q287rsihmd9j1tb
Tags: 1:0.12.4-2
* fixed the hardcoded depends
* added 3dp library

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *   Pure Data Packet system implementation: Packet Manager
3
 
 *   Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
4
 
 *
5
 
 *   This program is free software; you can redistribute it and/or modify
6
 
 *   it under the terms of the GNU General Public License as published by
7
 
 *   the Free Software Foundation; either version 2 of the License, or
8
 
 *   (at your option) any later version.
9
 
 *
10
 
 *   This program is distributed in the hope that it will be useful,
11
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *   GNU General Public License for more details.
14
 
 *
15
 
 *   You should have received a copy of the GNU General Public License
16
 
 *   along with this program; if not, write to the Free Software
17
 
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
 
 *
19
 
 */
20
 
 
21
 
 
22
 
 
23
 
#include <stdio.h>
24
 
#include <pthread.h>
25
 
#include <unistd.h>
26
 
#include <string.h>
27
 
#include "pdp_post.h"
28
 
#include "pdp_packet.h"
29
 
#include "pdp_mem.h"
30
 
#include "pdp_list.h"
31
 
#include "pdp_type.h"
32
 
#include "pdp_debug.h"
33
 
 
34
 
 
35
 
/* packet implementation. contains class and packet (instance) handling 
36
 
 
37
 
   some notes on packet operations.
38
 
   copy ro/rw and unregister are relatively straightforward
39
 
   packet creation can be done in 2 ways in this interface:
40
 
     create + reuse
41
 
   however, these methods should only be called by specific factory
42
 
   methods, so the user should only create packets using pdp_factory_newpacket
43
 
 
44
 
   reuse or create is thus the responsability of the factory methods for
45
 
   each packet type (class) implementation
46
 
 
47
 
 
48
 
*/
49
 
 
50
 
 
51
 
/* NOTE:
52
 
   the packet pool methods are called within the pool locks. this probably
53
 
   needs to change, because it will cause deadlocks for container packets (fobs) */
54
 
 
55
 
 
56
 
/* new implementation: probably just a minor adjustment: add the reuse fifo attached
57
 
   to type desc symbol name
58
 
   need to check and possibly eliminate hacks for non-pure packets
59
 
 
60
 
   pdp_packet_new:
61
 
      LOCK
62
 
      1. check reuse fifo
63
 
      2. empty -> create packet+return (search array)
64
 
      3. element -> check if type is correct, yes->pop+return, no->goto 1.
65
 
      UNLOCK
66
 
      4. wakeup
67
 
 
68
 
   pdp_packet_mark_unused
69
 
      
70
 
      1. check refcount. if > 1 dec  + exit
71
 
      2. if 1 put packet to sleep 
72
 
      3. dec refcount
73
 
      4. add to reuse fifo (no fifo -> create)
74
 
 
75
 
   pdp_packet_delete: analogous to mark_unused
76
 
   pdp_packet_copy_ro/rw: analogous to new
77
 
 
78
 
*/      
79
 
 
80
 
 
81
 
/* the pool */
82
 
#define PDP_INITIAL_POOL_SIZE 64
83
 
static int pdp_pool_size;
84
 
static t_pdp** pdp_pool;
85
 
 
86
 
/* mutex: protects the pool and reuse lists attached to symbols */
87
 
static pthread_mutex_t pdp_pool_mutex;
88
 
#define LOCK   pthread_mutex_lock   (&pdp_pool_mutex)
89
 
#define UNLOCK pthread_mutex_unlock (&pdp_pool_mutex)
90
 
 
91
 
/* the list of classes */
92
 
static t_pdp_list *class_list;
93
 
 
94
 
/* debug */
95
 
void
96
 
pdp_packet_print_debug(int packet)
97
 
{
98
 
    t_pdp *h = pdp_packet_header(packet);
99
 
    pdp_post("debug info for packet %d", packet);
100
 
    if (!h){
101
 
        pdp_post("invalid packet");
102
 
    }
103
 
    else{
104
 
        pdp_post ("\ttype: %d", h->type);
105
 
        pdp_post ("\tdesc: %s", h->desc ? h->desc->s_name : "unknown");
106
 
        pdp_post ("\tsize: %d", h->size);
107
 
        pdp_post ("\tflags: %x", h->flags);
108
 
        pdp_post ("\tusers: %d", h->users);
109
 
        pdp_post ("\tclass: %x", h->theclass);
110
 
    }
111
 
}
112
 
 
113
 
 
114
 
 
115
 
/* setup methods */
116
 
 
117
 
void 
118
 
pdp_packet_setup(void)
119
 
{
120
 
 
121
 
    pdp_pool_size = PDP_INITIAL_POOL_SIZE;
122
 
    pdp_pool = (t_pdp **)pdp_alloc(PDP_INITIAL_POOL_SIZE * sizeof(t_pdp *));
123
 
    bzero(pdp_pool, pdp_pool_size * sizeof(t_pdp *));
124
 
    class_list = pdp_list_new(0);
125
 
    pthread_mutex_init(&pdp_pool_mutex, NULL);
126
 
}
127
 
 
128
 
/* class methods */
129
 
t_pdp_class *pdp_class_new(t_pdp_symbol *type, t_pdp_factory_method create){
130
 
    t_pdp_class *c = (t_pdp_class *)pdp_alloc(sizeof(t_pdp_class));
131
 
    memset(c, 0, sizeof(t_pdp_class));
132
 
    c->create = create;
133
 
    c->type = type; // set type
134
 
    pdp_list_add(class_list, a_pointer, (t_pdp_word)((void *)c));
135
 
    return c;
136
 
}
137
 
 
138
 
/* the packet factory */
139
 
int pdp_factory_newpacket(t_pdp_symbol *type)
140
 
{
141
 
    int p;
142
 
    t_pdp_class *c;
143
 
    t_pdp_atom *a = class_list->first;
144
 
 
145
 
    /* try to reuse first 
146
 
       THINK: should this be the responsability of the type specific constructors,
147
 
       or should a packet allways be reusable (solution: depends on what the cleanup method returns??)
148
 
     */
149
 
    p = pdp_packet_reuse(type);
150
 
    if (-1 != p) return p;
151
 
 
152
 
 
153
 
    /* call class constructor */
154
 
    while(a){
155
 
        c = (t_pdp_class *)(a->w.w_pointer);
156
 
        if (c->type && pdp_type_description_match(type, c->type)){
157
 
            //pdp_post("method %x, type %s", c->create, type->s_name);
158
 
            return (c->create) ? (*c->create)(type) : -1;
159
 
        }
160
 
        a = a->next;
161
 
    }
162
 
    return -1;
163
 
}
164
 
 
165
 
static void
166
 
_pdp_pool_expand_nolock(void){
167
 
    int i;
168
 
 
169
 
    /* double the size */
170
 
    int new_pool_size = pdp_pool_size << 1;
171
 
    t_pdp **new_pool = (t_pdp **)pdp_alloc(new_pool_size * sizeof(t_pdp *));
172
 
    bzero(new_pool, new_pool_size * sizeof(t_pdp *));
173
 
    memcpy(new_pool, pdp_pool, pdp_pool_size * sizeof(t_pdp *));
174
 
    pdp_dealloc(pdp_pool);
175
 
    pdp_pool = new_pool;
176
 
    pdp_pool_size = new_pool_size;
177
 
}
178
 
 
179
 
 
180
 
 
181
 
 
182
 
/* private _pdp_packet methods */
183
 
 
184
 
/* packets can only be created and destroyed using these 2 methods */
185
 
/* it updates the mem usage and total packet count */
186
 
 
187
 
static void
188
 
_pdp_packet_dealloc_nolock(t_pdp *p)
189
 
{
190
 
    /* free memory */
191
 
    pdp_dealloc (p);
192
 
}
193
 
 
194
 
static t_pdp*
195
 
_pdp_packet_alloc_nolock(unsigned int datatype, unsigned int datasize)
196
 
{
197
 
    unsigned int totalsize = datasize + PDP_HEADER_SIZE;
198
 
    t_pdp *p = (t_pdp *)pdp_alloc(totalsize);
199
 
    if (p){
200
 
        memset(p, 0, PDP_HEADER_SIZE); //initialize header to 0
201
 
        p->type = datatype;
202
 
        p->size = totalsize;
203
 
        p->users = 1;
204
 
    }
205
 
    return p;
206
 
}
207
 
 
208
 
 
209
 
/* create a new packet and expand pool if necessary */
210
 
static int
211
 
_pdp_packet_create_nolock(unsigned int datatype, unsigned int datasize)
212
 
{
213
 
    int p = 0;
214
 
    while(1){
215
 
        for (; p < pdp_pool_size; p++){
216
 
            if (!pdp_pool[p]){
217
 
                /* found slot to store packet*/
218
 
                t_pdp *header = _pdp_packet_alloc_nolock(datatype, datasize);
219
 
                if (!header) return -1; // error allocating packet
220
 
                pdp_pool[p] = header;
221
 
                return p;
222
 
            }
223
 
        }
224
 
        /* no slot found, expand pool */
225
 
        _pdp_pool_expand_nolock();
226
 
    }
227
 
}
228
 
 
229
 
 
230
 
void 
231
 
pdp_packet_destroy(void)
232
 
{
233
 
    int i = 0;
234
 
    /* dealloc all the data in object stack */
235
 
    pdp_post("DEBUG: pdp_packet_destroy: clearing object pool.");
236
 
    while ((i < pdp_pool_size) && (pdp_pool[i])) _pdp_packet_dealloc_nolock(pdp_pool[i++]);
237
 
}
238
 
 
239
 
 
240
 
 
241
 
 
242
 
 
243
 
 
244
 
 
245
 
 
246
 
/* public pool operations: have to be thread safe so each entry point
247
 
   locks the mutex */
248
 
 
249
 
 
250
 
/* create a new packet.
251
 
   this should only be used by type specific factory methods, and only if the
252
 
   reuse method fails, since it will always create a new packet */
253
 
int 
254
 
pdp_packet_create(unsigned int datatype, unsigned int datasize /*without header*/)
255
 
{
256
 
    int packet;
257
 
    LOCK;
258
 
    packet = _pdp_packet_create_nolock(datatype, datasize);
259
 
    UNLOCK;
260
 
    return packet;
261
 
}
262
 
 
263
 
 
264
 
/* return a new packet.
265
 
   it tries to reuse a packet based on
266
 
    1. matching data size
267
 
    2. abscence of destructor (which SHOULD mean there are no enclosed references)
268
 
 
269
 
    it obviously can't use the reuse fifo tagged to a symbolic type description
270
 
 
271
 
    ALWAYS USE pdp_packet_reuse BEFORE calling pdp_packet_new if possible
272
 
    use both ONLY IN CONSTRUCTORS !!!
273
 
 
274
 
    use pdp_packet_factory to create packets as a "user"
275
 
 
276
 
    this is a summary of all internal packet creation mechanisms:
277
 
 
278
 
     -> pdp_packet_reuse, which uses symbolic type descriptions, and should work for all packet types
279
 
        it returns an initialized container (meta = correct, data = garbage)
280
 
 
281
 
     -> pdp_packet_new, which only works for non-pure packets, and reuses packets based on data type
282
 
        it returns a pure packet (meta + data = garbage)
283
 
 
284
 
     -> pdp_packet_create, like pdp_packet_new, only it always creates a new packet
285
 
 
286
 
 
287
 
 
288
 
*/
289
 
 
290
 
int 
291
 
pdp_packet_new(unsigned int datatype, unsigned int datasize)
292
 
{
293
 
    t_pdp *header;
294
 
    int packet;
295
 
    LOCK;
296
 
    for (packet = 0; packet < pdp_pool_size; packet++){
297
 
        header = pdp_pool[packet];
298
 
        /* check data size */
299
 
        if (header 
300
 
            && header->users == 0 // must be unused
301
 
            && header->size == datasize + PDP_HEADER_SIZE // must be same size
302
 
            && !(header->theclass && header->theclass->cleanup)){ // must be pure packet (no destructor)
303
 
 
304
 
            /* ok, got one. initialize */
305
 
            memset(header, 0, PDP_HEADER_SIZE);
306
 
            header->users = 1;
307
 
            header->type = datatype;
308
 
            header->size = datasize + PDP_HEADER_SIZE;
309
 
 
310
 
            UNLOCK; //EXIT1
311
 
            return packet;
312
 
        }
313
 
    }
314
 
 
315
 
    /* no usable non-pure packet found, create a new one */
316
 
 
317
 
    UNLOCK; //EXIT2
318
 
    return pdp_packet_create(datatype, datasize);
319
 
 
320
 
 
321
 
 
322
 
}
323
 
 
324
 
 
325
 
/* internal method to add a packet to a packet type
326
 
   description symbol's unused packet fifo */
327
 
void
328
 
_pdp_packet_save_nolock(int packet)
329
 
{
330
 
    t_pdp *header = pdp_packet_header(packet);
331
 
    t_pdp_symbol *s;
332
 
    PDP_ASSERT(header);
333
 
    PDP_ASSERT(header->users == 0);
334
 
    PDP_ASSERT(header->desc);
335
 
    s = header->desc;
336
 
    if (!s->s_reusefifo) s->s_reusefifo = pdp_list_new(0);
337
 
    pdp_list_add(s->s_reusefifo, a_packet, (t_pdp_word)packet);
338
 
}
339
 
 
340
 
/* this will revive a packet matching a certain type description
341
 
   no wildcards are allowed */
342
 
int
343
 
pdp_packet_reuse(t_pdp_symbol *type_description)
344
 
{
345
 
    int packet = -1;
346
 
    t_pdp *header = 0;
347
 
    t_pdp_list *l = 0;
348
 
    LOCK;
349
 
    if (!type_description || !(l = type_description->s_reusefifo)) goto exit;
350
 
    while(l->elements){
351
 
        packet = pdp_list_pop(l).w_packet;
352
 
        header = pdp_packet_header(packet);
353
 
 
354
 
        /* check if reuse fifo is consistent (packet unused + correct type)
355
 
           packet could be deleted and replaced with another one, or
356
 
           revived without the index updated (it's a "hint cache") */
357
 
 
358
 
        if (header->users == 0){
359
 
            /* check if type matches */
360
 
            if (pdp_type_description_match(header->desc, type_description)){
361
 
                header->users++; // revive
362
 
                goto exit;
363
 
            }
364
 
            /* if not, add the packet to the correct reuse fifo */
365
 
            else{
366
 
                _pdp_packet_save_nolock(packet);
367
 
            }
368
 
        }
369
 
 
370
 
        /* remove dangling refs */
371
 
        header = 0;
372
 
        packet = -1;
373
 
    }
374
 
    
375
 
  exit:
376
 
    UNLOCK;
377
 
    if (header && header->theclass && header->theclass->wakeup){
378
 
        header->theclass->wakeup(header); // revive if necessary
379
 
    }
380
 
    return packet;
381
 
}
382
 
 
383
 
/* find all unused packets in pool, marked as used (to protect from other reapers)
384
 
   and return them as a list. non-pure packets are not revived */
385
 
 
386
 
 
387
 
 
388
 
 
389
 
 
390
 
/* this returns a copy of a packet for read only access. 
391
 
   (increases refcount of the packet -> packet will become readonly if it was
392
 
   writable, i.e. had rc=1 */
393
 
 
394
 
int
395
 
pdp_packet_copy_ro(int handle)
396
 
{
397
 
    t_pdp* header;
398
 
 
399
 
    if (header = pdp_packet_header(handle)){
400
 
        PDP_ASSERT(header->users); // consistency check
401
 
        LOCK;
402
 
        header->users++;           // increment reference count
403
 
        UNLOCK;
404
 
    }
405
 
    else handle = -1;
406
 
    return handle;
407
 
}
408
 
 
409
 
/* clone a packet: create a new packet with the same
410
 
   type as the source packet */
411
 
 
412
 
int
413
 
pdp_packet_clone_rw(int handle)
414
 
{
415
 
    t_pdp* header;
416
 
    int new_handle = -1;
417
 
 
418
 
 
419
 
    if (header = pdp_packet_header(handle)){
420
 
        /* consistency checks */
421
 
        PDP_ASSERT(header->users);
422
 
        PDP_ASSERT(header->desc);
423
 
 
424
 
        /* first try to reuse old packet */
425
 
        new_handle = pdp_packet_reuse(header->desc);
426
 
 
427
 
        /* if this failed, create a new one using the central packet factory method */
428
 
        if (-1 == new_handle) new_handle = pdp_factory_newpacket(header->desc);
429
 
 
430
 
        /* if the factory method failed cline it manually */
431
 
        if (-1 == new_handle) {
432
 
            t_pdp *new_header;
433
 
            //pdp_post("WARNING: pdp_clone_rw: working around non-implemented factory method.");
434
 
            new_handle = pdp_packet_new(header->type, header->size - PDP_HEADER_SIZE);
435
 
            new_header = pdp_packet_header(new_handle);
436
 
            if (new_header){
437
 
                memcpy(new_header, header, PDP_HEADER_SIZE);
438
 
            }
439
 
        }
440
 
    }
441
 
 
442
 
    return new_handle;
443
 
}
444
 
 
445
 
/* return a copy of a packet (clone + copy data) */
446
 
int
447
 
pdp_packet_copy_rw(int handle)
448
 
{
449
 
    t_pdp *header, *new_header;
450
 
    int new_handle = -1;
451
 
 
452
 
    if (!(header = pdp_packet_header(handle))) return -1;
453
 
 
454
 
    /* check if we are allowed to copy */
455
 
    if (header->flags & PDP_FLAG_DONOTCOPY) return -1;
456
 
 
457
 
    /* get target packet */
458
 
    new_handle = pdp_packet_clone_rw(handle);
459
 
    if (-1 == new_handle) return -1;
460
 
    new_header = pdp_packet_header(new_handle);
461
 
 
462
 
    /* if there is a copy method, use that one */
463
 
    if (header->theclass && header->theclass->copy){
464
 
        header->theclass->copy(header, new_header);
465
 
    }
466
 
 
467
 
    /* otherwize copy the data verbatim */
468
 
    else {
469
 
        memcpy(pdp_packet_data(new_handle),
470
 
               pdp_packet_data(handle),
471
 
               pdp_packet_data_size(handle));
472
 
    }
473
 
 
474
 
    return new_handle;
475
 
    
476
 
}
477
 
 
478
 
 
479
 
/* decrement refcount */
480
 
void pdp_packet_mark_unused(int handle)
481
 
{
482
 
    t_pdp *header;
483
 
    if (!(header = pdp_packet_header(handle))) return;
484
 
    
485
 
    PDP_ASSERT(header->users); // consistency check
486
 
 
487
 
    LOCK;
488
 
 
489
 
    /* just decrement refcount */
490
 
    if (header->users > 1){
491
 
        header->users--;
492
 
    }
493
 
 
494
 
    /* put packet to sleep if refcount 1->0 */
495
 
    else {
496
 
        if (header->theclass && header->theclass->sleep){
497
 
            /* call sleep method (if any) outside of lock
498
 
               while the packet is still alive, so it won't be
499
 
               acclaimed by another thread */
500
 
            UNLOCK;
501
 
            header->theclass->sleep(header); 
502
 
            LOCK;
503
 
        }
504
 
        /* clear refcount & save in fifo for later use */
505
 
        header->users = 0;
506
 
        if (header->desc) // sleep could have destructed packet..
507
 
            _pdp_packet_save_nolock(handle);
508
 
    }
509
 
 
510
 
    UNLOCK;
511
 
}
512
 
 
513
 
 
514
 
 
515
 
/* delete a packet. rc needs to be == 1 */
516
 
void pdp_packet_delete(int handle)
517
 
{
518
 
    t_pdp *header;
519
 
    header = pdp_packet_header(handle);
520
 
    PDP_ASSERT(header);
521
 
    PDP_ASSERT(header->users == 1); // consistency check
522
 
 
523
 
    LOCK;
524
 
    
525
 
    if (header->theclass && header->theclass->cleanup){
526
 
        /* call cleanup method (if any) outside of lock
527
 
           while the packet is still alive, so it won't be
528
 
           acclaimed by another thread */
529
 
        UNLOCK;
530
 
        header->theclass->cleanup(header); 
531
 
        LOCK;
532
 
    }
533
 
 
534
 
    /* delete the packet */
535
 
    pdp_pool[handle] = 0;
536
 
    _pdp_packet_dealloc_nolock(header);
537
 
    
538
 
 
539
 
    UNLOCK;
540
 
}
541
 
 
542
 
 
543
 
 
544
 
 
545
 
 
546
 
 
547
 
 
548
 
/* public data access methods */
549
 
 
550
 
t_pdp*
551
 
pdp_packet_header(int handle)
552
 
{
553
 
    if ((handle >= 0) && (handle < pdp_pool_size)) return pdp_pool[handle];
554
 
    else return 0;
555
 
}
556
 
 
557
 
void*
558
 
pdp_packet_subheader(int handle)
559
 
{
560
 
    t_pdp* header = pdp_packet_header(handle);
561
 
    if (!header) return 0;
562
 
    return (void *)(&header->info.raw);
563
 
}
564
 
 
565
 
void*
566
 
pdp_packet_data(int handle)
567
 
{
568
 
    t_pdp *h;
569
 
    if ((handle >= 0) && (handle < pdp_pool_size)) 
570
 
        {
571
 
            h = pdp_pool[handle];
572
 
            if (!h) return 0;
573
 
            return (char *)(h) + PDP_HEADER_SIZE;
574
 
        }
575
 
    else return 0;
576
 
}
577
 
 
578
 
int
579
 
pdp_packet_data_size(int handle)
580
 
{
581
 
    t_pdp *h;
582
 
    if ((handle >= 0) && (handle < pdp_pool_size)) 
583
 
        {
584
 
            h = pdp_pool[handle];
585
 
            if (!h) return 0;
586
 
            return h->size - PDP_HEADER_SIZE;
587
 
        }
588
 
    else return 0;    
589
 
}
590
 
 
591
 
 
592
 
 
593
 
 
594
 
int pdp_packet_writable(int packet) /* returns true if packet is writable */
595
 
{
596
 
    t_pdp *h = pdp_packet_header(packet);
597
 
    if (!h) return 0;
598
 
    return (h->users == 1);
599
 
}
600
 
 
601
 
void pdp_packet_replace_with_writable(int *packet) /* replaces a packet with a writable copy */
602
 
{
603
 
    int new_p;
604
 
    if (!pdp_packet_writable(*packet)){
605
 
        new_p = pdp_packet_copy_rw(*packet);
606
 
        pdp_packet_mark_unused(*packet);
607
 
        *packet = new_p;
608
 
    }
609
 
        
610
 
}
611
 
 
612
 
/* pool stuff */
613
 
 
614
 
int
615
 
pdp_pool_collect_garbage(void)
616
 
{
617
 
    pdp_post("ERROR: garbage collector not implemented");
618
 
    return 0;
619
 
}
620
 
 
621
 
void
622
 
pdp_pool_set_max_mem_usage(int max)
623
 
{
624
 
    pdp_post("ERROR: mem limit not implemented");
625
 
}
626
 
 
627
 
 
628
 
 
629
 
 
630
 
 
631
 
 
632
 
#ifdef __cplusplus
633
 
}
634
 
#endif