source: svn/newcon3bcm2_21bu/BSEAV/lib/utils/bioatom.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 59.2 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2007-2011, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: bioatom.c $
11 * $brcm_Revision: 44 $
12 * $brcm_Date: 5/26/11 2:42p $
13 *
14 * Module Description:
15 *
16 * Scatter gatther unit
17 *
18 * Revision History:
19 *
20 * $brcm_Log: /BSEAV/lib/utils/bioatom.c $
21 *
22 * 44   5/26/11 2:42p vsilyaev
23 * SW7425-615: Simplified debug code
24 *
25 * 43   12/6/10 6:23p vsilyaev
26 * SW35230-1953: Added function to return vector array and size
27 *
28 * 42   8/5/10 1:15p vsilyaev
29 * SW7405-4681: Added function to return position in the bitstream
30 *
31 * 41   5/6/10 3:39p vsilyaev
32 * SW7405-3773: Improved debug messages
33 *
34 * 40   2/2/10 3:52p vsilyaev
35 * SW7468-69: Added function to help switch between bitstream and
36 * bytestream
37 *
38 * 39   12/2/09 12:04p vsilyaev
39 * SW7405-3368: Removed unnecessary const
40 *
41 * 38   12/2/09 11:53a vsilyaev
42 * SW7405-3368: Fixed implementation of batom_cursor_compare
43 *
44 * 37   12/2/09 11:28a vsilyaev
45 * SW7405-3368: Added batom_cursor_compare function
46 *
47 * dev_bdvd_v3.0_issue15380/1   12/2/09 11:22a gooslin
48 * Add cursor compare function
49 *
50 * 36   10/28/09 1:17p vsilyaev
51 * SW7405-3311: Fixed comment
52 *
53 * 35   9/29/09 2:44p vsilyaev
54 * SWDEPRECATED-3624: Optimized bit reading functions
55 *
56 * 34   6/8/09 7:09p vsilyaev
57 * PR 55554: Fixed handling of huge frames in MP4 stream
58 *
59 * 33   3/6/09 12:52p vsilyaev
60 * PR 52903: Added the 'break;' statement after BDBG_ASSERT(0)
61 *
62 * 32   11/4/08 9:57a vsilyaev
63 * PR 48608: Merged code that alligns audio/video streams after seek.
64 *
65 * 31   10/29/08 5:58p vsilyaev
66 * PR 48003: Updated batom_accum_add_range to handle large block sizes
67 *
68 * bdvd_v1.4/bdvd_v1.42/fix_bdvd_v1.42_pr11402/1   11/1/08 7:43p gooslin
69 * Cleanup A/V sync modifications
70 *
71 * bdvd_v1.4/2   10/17/08 3:44p gooslin
72 * PR_11182 [   ].  Add fist pass MP4 support
73 *
74 * bdvd_v1.4/dev_bdvd_v1.4_pr11182/1   10/17/08 10:31a gooslin
75 * Fix compile issue with debug enabled
76 *
77 * bdvd_v1.4/1   9/23/08 9:51p gooslin
78 * PR_10564 [   ].  Fix A/V sync issue when playing ASF files from a
79 * point other than the origin
80 *
81 * fix_bdvd_v1.4_pr10564/1   9/23/08 4:11p gooslin
82 * Add function to push an atom onto the head of the list
83 *
84 * 30   6/27/08 12:56p vsilyaev
85 * PR 41869: Fixed formatting of an hex dump
86 *
87 * 29   6/12/08 3:07p vsilyaev
88 * PR 43607: Renamed alloc and free to bmem_alloc and bmem_free
89 *
90 * 28   3/4/08 12:24p vsilyaev
91 * PR 39818: Relaxed test is batom_cursor_copy
92 *
93 * 27   3/3/08 12:28p vsilyaev
94 * PR 39818: Fixed cursor update after accum_trim, imporved diagnostic and
95 * comments
96 *
97 * 26   9/28/07 12:08p vishk
98 * PR 35216: LIB-Converity (CID 3046): OVERRUN_STATIC,
99 *
100 * 25   8/10/07 12:27p vsilyaev
101 * PR 32813: Added functions to return pointer to the cursor's continuous
102 * buffer
103 *
104 * 24   7/26/07 2:01p vsilyaev
105 * PR 32813: Added inline versions of some cursor functions
106 *
107 * 23   7/12/07 3:41p vsilyaev
108 * PR 32846: Added function to return atom's vector array
109 *
110 * 22   7/9/07 3:51p vsilyaev
111 * PR 32846: Optimized operations with batom_t
112 *
113 * 21   6/14/07 1:53p vsilyaev
114 * PR 31887: Added function to directly copy data between accumulators
115 *
116 * 20   5/25/07 7:17p vsilyaev
117 * PR 25701: Added documentation
118 *
119 * 19   5/24/07 10:25a vsilyaev
120 * PR 29815: Added function batom_empty to create empty atom (e.g. without
121 * payload), fixed b_atom_refill, improved debug output
122 *
123 * 18   5/23/07 9:16p vsilyaev
124 * PR 29815: Added more tests that verify that pipe wouldn't have atoms
125 * which are already dead
126 *
127 * 17   5/21/07 5:53p vsilyaev
128 * PR 29815: Fixed improper use of assert, when partioning accumulator
129 * with anonymous data
130 *
131 * 16   5/18/07 5:11p vsilyaev
132 * PR 28631: Optimized (reduced code size) of batom_cursor_next and
133 * b_atom_cursor_refill
134 *
135 * 15   5/18/07 11:27a vsilyaev
136 * PR 28631: Fixed off by one comparison
137 *
138 * 14   5/18/07 12:36a vsilyaev
139 * PR 31188: Added functions to read 24 bit integers
140 *
141 * 13   5/10/07 5:07p vsilyaev
142 * PR 28631: Truncate unsigned int before comparing with signed int
143 *
144 * 12   5/1/07 5:14p vsilyaev
145 * PR 28631: Fixed clearing of accumulator
146 *
147 * 11   5/1/07 11:16a vsilyaev
148 * PR 28631: Added functions to dump content of accumulator, atom and
149 * cursor
150 *
151 * 10   3/27/07 7:25p vsilyaev
152 * PR 29125: Added bit reader
153 *
154 * 9   3/2/07 5:31p vsilyaev
155 * PR 25701: Added support to splitting range in multiple vectors
156 *
157 * 8   3/1/07 7:05p vsilyaev
158 * PR 25701: Added function to return number of vectors in the atom
159 *
160 * 7   2/20/07 2:28p vsilyaev
161 * PR 25701: Use self-referential owner for anonymous data, it guarantees
162 * that atom is not released if only anonymous data is referenced
163 *
164 * 6   2/20/07 10:18a vsilyaev
165 * PR 25701: Added batom_extract
166 *
167 * 5   2/15/07 3:12p vsilyaev
168 * PR 25701: Added code to handle parsing during resource starvation
169 *
170 * 4   2/14/07 5:46p vsilyaev
171 * PR 25701: Added code to dump content/status of allocator
172 *
173 * 3   2/9/07 7:28p vsilyaev
174 * PR 25701: Added new function to combine range and pipe (frequent case
175 * when PES header appended to the payload)
176 *
177 * 2   2/6/07 6:47p vsilyaev
178 * PR 25701: Added batom_accum_trim and batom_accum_extract to manipulate
179 * acccumulators based on cursors
180 *
181 * 1   2/5/07 5:28p vsilyaev
182 * PR 25701:Portions of stackable parsing framework
183 *
184 *******************************************************************************/
185#include "bstd.h"
186#include "balloc.h"
187#include "blst_squeue.h"
188#include "blst_list.h"
189#include "bpool.h"
190#include "barena.h"
191#include "bioatom.h"
192#include "bkni.h"
193
194BDBG_MODULE(batom);
195
196#define BDBG_MSG_TRACE(x) /* BDBG_MSG(x) */
197#define BDBG_MSG_FLOW(x) /* BDBG_MSG(x) */
198
199
200#define B_ATOM_ALLOC_POOL       0xA0
201#define B_ATOM_ALLOC_ARENA      0xA1
202#define B_ATOM_ALLOC_ALLOC      0xA2
203
204#define B_ATOM_TYPE_ARRAY       0
205#define B_ATOM_TYPE_CLONE       1
206#define B_ATOM_TYPE_INVALID  0xBF
207
208#define B_ATOM_TRUNCATE_SIZE(size) ((size) & 0x7FFFFFFFul)
209
210
211struct batom {
212        /* members are arranged in a way that they would be packed where appropriate */
213        BLST_SQ_ENTRY(batom) pipe_link; /* link for the pipe */
214        uint16_t ref_cnt; /* number of references to array */
215        uint8_t atom_type; /* B_ATOM_TYPE_XXX */
216        uint8_t alloc_type; /* kind of allocator used to create the atom */
217        union {
218                struct {
219                        uint16_t count; /* number of entrries in the array */
220                        size_t length;  /* total length of data */
221                        /* variable length array
222                        *  batom_vec vec[nvec];
223                        **/
224                        /* variable length array
225                        *  batom *owner[nvec];
226                        *                        */
227                } array;
228                struct {
229                        batom_t parent; /* pointer to the parent atom */
230                        batom_t master; /* pointer to the last atom in the chain */
231                } clone;
232        } u;
233        const batom_user  *ops;       
234        batom_factory_t factory;
235        /* variable length array
236        *     uint8_t udata[user_data];
237        */
238};
239
240BDBG_OBJECT_ID(batom_accum_t);
241
242#define B_ATOM_USER_PTR(atom) (void *)((uint8_t *)(atom)+ sizeof(*(atom))+((atom)->atom_type==B_ATOM_TYPE_ARRAY?((unsigned)(atom)->u.array.count)*(sizeof(batom_vec)+sizeof(batom_t)):0))
243#define B_ATOM_VEC_PTR_ARRAY(atom)  (batom_vec*)((uint8_t *)(atom)+sizeof(*(atom)))
244/* #define B_ATOM_VEC_PTR(atom) ((atom)->atom_type==B_ATOM_TYPE_ARRAY?B_ATOM_VEC_PTR_ARRAY(atom):B_ATOM_VEC_PTR_ARRAY((atom)->u.clone.master)) */
245#define B_ATOM_PTR_ARRAY(atom) (batom_t*)((uint8_t *)(atom)+sizeof(*(atom))+((unsigned)(atom)->u.array.count)*(sizeof(batom_vec)))
246#define B_ATOM_MASTER(atom) ((atom)->atom_type==B_ATOM_TYPE_ARRAY?atom:(atom)->u.clone.master)
247
248#define B_ATOM_INIT_VEC 2
249#define B_ATOM_USER_SIZE (3*sizeof(unsigned))
250#define B_ATOM_INIT_SIZE        (sizeof(struct batom)+B_ATOM_INIT_VEC*(sizeof(batom_vec)+sizeof(batom_t))+B_ATOM_USER_SIZE)
251
252
253#define B_ATOM_ACC_INIT_VEC     16
254struct batom_accum {
255        batom_factory_t factory;
256        uint16_t nvecs; /* number of allocated entries */   
257        uint16_t count; /* number of entries in the array */
258        size_t length;  /* total length of data accumulated */
259        batom_vec *vec; /* pointer to the vector table */
260        batom_t  *owner; /* pointer to the owner table */
261        BDBG_OBJECT(batom_accum_t)
262        /* inline vecs */
263        /* inline owner */
264};
265
266BDBG_OBJECT_ID(batom_factory_t);
267
268struct batom_factory {
269        bpool_t pool;
270        barena_t arena;
271        balloc_iface_t alloc; 
272        batom_factory_stats stats;
273        BDBG_OBJECT(batom_factory_t)
274};
275
276BDBG_OBJECT_ID(batom_pipe_t);
277struct batom_pipe {
278        BLST_SQ_HEAD(b_atom_pipe_t, batom) atoms;
279        batom_factory_t factory;
280        unsigned push_cnt;
281        unsigned pop_cnt;
282        BDBG_OBJECT(batom_pipe_t)
283};
284
285batom_factory_t
286batom_factory_create(balloc_iface_t alloc, size_t natoms)
287{
288        batom_factory_t factory;
289
290        factory = alloc->bmem_alloc(alloc, sizeof(*factory));
291        BDBG_MSG_TRACE(("batom_factory_create: %#lx ATOM_INIT_SIZE %u", (unsigned long)factory, B_ATOM_INIT_SIZE));
292        if (!factory) {
293                goto err_alloc;
294        }
295        BDBG_OBJECT_INIT(factory, batom_factory_t);
296        factory->alloc = alloc;
297        factory->pool = bpool_create(alloc, (3*natoms)/4, B_ATOM_INIT_SIZE ); /* 75% of total atoms shall be allocatable from the pool */
298        if (!factory->pool) {
299                goto err_pool;
300        }
301        factory->arena = barena_create(alloc, B_ATOM_INIT_SIZE * (natoms/4)); /* 25% of total atoms shall be allocated from the arena */
302        if (!factory->arena) {
303                goto err_arena;
304        }
305        BKNI_Memset(&factory->stats, 0 , sizeof(factory->stats));
306        return factory;
307
308err_arena:
309        bpool_destroy(factory->pool);
310err_pool:
311        BDBG_OBJECT_DESTROY(factory, batom_factory_t);
312        alloc->bmem_free(alloc, factory);
313err_alloc:
314        return NULL;
315}
316
317void
318batom_factory_destroy(batom_factory_t factory)
319{
320        balloc_iface_t alloc;
321        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
322        alloc = factory->alloc;
323        barena_destroy(factory->arena);
324        bpool_destroy(factory->pool);
325        BDBG_OBJECT_DESTROY(factory, batom_factory_t);
326        alloc->bmem_free(alloc, factory);
327        return;
328
329}
330
331void
332batom_factory_get_stats(batom_factory_t factory, batom_factory_stats *stats)
333{
334        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
335        *stats = factory->stats;
336        bpool_get_status(factory->pool, &stats->pool_status);
337        return;
338}
339
340void
341batom_factory_dump(batom_factory_t factory)
342{
343        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
344        BDBG_WRN(("batom_factory_dump: atoms[live:%u allocated:%u freed:%u] alloc[pool:%u/%u/%u arena:%u/%u/%u alloc:%u/%u]", factory->stats.atom_live, factory->stats.atom_allocated, factory->stats.atom_freed, factory->stats.alloc_pool, factory->stats.free_pool, factory->stats.full_pool, factory->stats.alloc_arena, factory->stats.free_arena, factory->stats.full_arena, factory->stats.alloc_alloc, factory->stats.free_alloc));
345        bpool_dump(factory->pool);
346        barena_dump(factory->arena);
347        return;
348}
349
350static const batom_user b_atom_default_ops = {
351        NULL,
352        0
353};
354
355
356static void
357b_io_accum_init(batom_accum_t acc)
358{
359        acc->nvecs = B_ATOM_ACC_INIT_VEC;
360        acc->vec = (batom_vec *)((uint8_t *)acc + sizeof(*acc));
361        acc->owner = (batom_t*)((uint8_t *)acc->vec + B_ATOM_ACC_INIT_VEC*sizeof(batom_vec));
362        return;
363}
364
365#if 0
366static void
367b_atom_lock(batom_t atom)
368{
369        atom->ref_cnt++;
370        BDBG_ASSERT(atom->ref_cnt>0);
371}
372#else
373#define b_atom_lock(atom) do {(atom)->ref_cnt++;BDBG_ASSERT((atom)->ref_cnt>0);}while(0)
374#endif
375
376void
377batom_lock(batom_t atom)
378{
379        batom_factory_t factory;
380        BDBG_MSG_TRACE(("batom_lock: >%#lx", (unsigned long)atom));
381        BDBG_ASSERT(atom);
382
383        factory = atom->factory;
384        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
385        b_atom_lock(atom);
386        BDBG_MSG_TRACE(("batom_lock: <%#lx %u", (unsigned long)atom, atom->ref_cnt));
387        return;
388}
389
390/* this function callled recursively */
391void
392batom_release(batom_t atom)
393{
394        batom_factory_t factory;
395        BDBG_ASSERT(atom);
396        BDBG_MSG_TRACE(("batom_release: >%#lx", (unsigned long)atom));
397
398        factory = atom->factory;
399        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
400
401        BDBG_MSG_TRACE(("batom_release: %#lx %u", (unsigned long)atom, atom->ref_cnt));
402        BDBG_ASSERT(atom->ref_cnt>0);
403        atom->ref_cnt--;
404        if (atom->ref_cnt>0) {
405                BDBG_MSG_TRACE(("batom_release: <%#lx %u", (unsigned long)atom, atom->ref_cnt));
406                return;
407        }
408        BDBG_MSG_TRACE(("batom_release: %#lx free", (unsigned long)atom));
409        BDBG_ASSERT(atom->ops);
410        if(atom->ops->user_free) {
411                BDBG_MSG_TRACE(("batom_release: %#lx user free+", (unsigned long)atom));
412                atom->ops->user_free(atom, B_ATOM_USER_PTR(atom));
413                BDBG_MSG_TRACE(("batom_release: %#lx user free-", (unsigned long)atom));
414                BDBG_ASSERT(atom->ref_cnt==0);/* free shall not increase reference counter */
415        }
416
417        switch(atom->atom_type) {
418        case B_ATOM_TYPE_CLONE:
419                batom_release(atom->u.clone.parent);
420                break;
421        default:
422                BDBG_ASSERT(0);
423        break;
424        case B_ATOM_TYPE_ARRAY:
425                {
426                unsigned i;
427                batom_t *owners=B_ATOM_PTR_ARRAY(atom);
428#if BDBG_DEBUG_BUILD
429                        batom_vec *vecs = B_ATOM_VEC_PTR_ARRAY(atom);
430                        for(i=0;i<atom->u.array.count;i++) {
431                                vecs[i].base = NULL;
432                        }
433#endif
434                        for(i=0;i<atom->u.array.count;i++) {
435                                BDBG_MSG_TRACE(("batom_release: %#lx %u:%lx", (unsigned long)atom, i, (unsigned long)owners[i]));
436                                BDBG_ASSERT(owners[i]);
437                                if (owners[i]!=atom) {
438                                        batom_release(owners[i]);
439                                }
440                        }
441                }
442        }
443        BDBG_ASSERT(atom->ref_cnt==0); /* recursive releases shall not lock this object either */
444        BDBG_ASSERT(factory->stats.atom_live>0);
445        factory->stats.atom_live--;
446        factory->stats.atom_freed++;
447        atom->atom_type = B_ATOM_TYPE_INVALID;
448        atom->factory = NULL;
449        BDBG_ASSERT(BLST_SQ_NEXT(atom, pipe_link) == NULL);
450        switch(atom->alloc_type) {
451        case B_ATOM_ALLOC_POOL:
452                atom->alloc_type = 0;
453                factory->stats.free_pool++;
454                bpool_free(factory->pool, atom);
455                break;
456        case B_ATOM_ALLOC_ARENA:
457                atom->alloc_type = 0;
458                factory->stats.free_arena++;
459                barena_free(factory->arena, atom);
460                break;
461        default:
462                BDBG_ASSERT(0);
463        break;
464        case B_ATOM_ALLOC_ALLOC:
465                atom->alloc_type = 0;
466                factory->stats.free_alloc++;
467                factory->alloc->bmem_free(factory->alloc, atom);
468                break;
469        }
470        return;
471}
472
473batom_accum_t
474batom_accum_create(batom_factory_t factory)
475{
476        batom_accum_t acc;
477
478        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
479        acc = factory->alloc->bmem_alloc(factory->alloc, sizeof(*acc)+B_ATOM_ACC_INIT_VEC*(sizeof(batom_vec)+sizeof(batom_t)));
480        if (!acc) {
481                return NULL;
482        }
483        BDBG_OBJECT_INIT(acc, batom_accum_t);
484        acc->factory = factory;
485        b_io_accum_init(acc);
486        acc->count = 0;
487        acc->length = 0;
488        return acc;
489}
490
491void
492batom_accum_clear(batom_accum_t acc)
493{
494        unsigned count;
495        batom_t *owner;
496        BDBG_MSG_TRACE(("batom_accum_clear: >%#lx", (unsigned long)acc));
497        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
498        count = acc->count;
499        owner = acc->owner;
500        while(count>0) {
501                if(*owner) {
502                        batom_release(*owner);
503                }
504                count--;
505                owner++;
506        }
507        acc->count = 0;
508        acc->length = 0;
509        BDBG_MSG_TRACE(("batom_accum_clear: <%#lx", (unsigned long)acc));
510        return;
511}
512
513void
514batom_accum_destroy(batom_accum_t acc)
515{
516        batom_factory_t factory;
517        balloc_iface_t alloc;
518        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
519        factory=acc->factory;
520        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
521        batom_accum_clear(acc);
522        alloc = factory->alloc;
523        if((uint8_t *)acc->vec != (uint8_t *)acc+sizeof(*acc)) {
524                alloc->bmem_free(alloc, acc->vec);
525        }
526        BDBG_OBJECT_DESTROY(acc, batom_accum_t);
527        alloc->bmem_free(alloc, acc);
528        return;
529}
530
531const batom_vec *
532batom_accum_get_vectors( batom_accum_t acc,  unsigned *nvecs )
533{
534        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
535    BDBG_ASSERT(nvecs);
536    *nvecs = acc->count;
537    return acc->vec;
538}
539
540
541static bool
542b_io_acc_grow(batom_accum_t acc)
543{
544        batom_factory_t factory;
545        void *ptr;
546        unsigned nvecs;
547        unsigned old_nvecs;
548
549        BDBG_MSG_TRACE(("b_io_acc_grow: >%#lx", (unsigned long)acc));
550
551        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
552        factory = acc->factory;
553        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
554        old_nvecs = acc->nvecs;
555        nvecs = old_nvecs*2;
556        if (nvecs>BATOM_VEC_MAX_SIZE) {
557                BDBG_WRN(("b_io_acc_grow: %#lx to many entries in the accumulator (%u)", (unsigned long)acc, (unsigned)nvecs));
558                return false;
559        }
560
561        /* allocate new array */
562        ptr = factory->alloc->bmem_alloc(factory->alloc, nvecs*(sizeof(batom_vec)+sizeof(batom_t)));
563        if(!ptr) {
564                BDBG_WRN(("b_io_acc_grow: %#lx can't allocate %u bytes", (unsigned long)acc, (unsigned)nvecs*(sizeof(batom_vec)+sizeof(batom_t))));
565                return false;
566        }
567        BKNI_Memcpy(ptr, acc->vec, old_nvecs*sizeof(batom_vec));
568        BKNI_Memcpy( (uint8_t *)ptr + nvecs*sizeof(batom_vec), acc->owner, old_nvecs*sizeof(batom_t));
569        if( (uint8_t *)acc->vec != (uint8_t *)acc+sizeof(*acc)) {
570                /* free previously allocated block */
571                factory->alloc->bmem_free(factory->alloc, acc->vec);
572        }
573        acc->nvecs= nvecs;
574        acc->vec = ptr;
575        acc->owner = (batom_t *)((uint8_t *)ptr + nvecs*sizeof(batom_vec));
576        BDBG_MSG_TRACE(("b_io_acc_grow: <%#lx %u", (unsigned long)acc, acc->count));
577        return true;
578}
579
580size_t 
581batom_accum_len(batom_accum_t acc)
582{
583        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
584        BDBG_MSG_TRACE(("batom_accum_len: %#lx %u", (unsigned long)acc, acc->length));
585        return acc->length;
586}
587
588void
589batom_accum_add_vec(batom_accum_t acc, const batom_vec *vec)
590{
591        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
592        BDBG_ASSERT(vec);
593        BDBG_MSG_TRACE(("batom_accum_add_vec: >%#lx %#lx %u:%u", (unsigned long)acc, (unsigned long)vec, acc->count, acc->nvecs));
594        if (acc->count >= acc->nvecs) {
595                if(!b_io_acc_grow(acc)) {
596                        return;
597                }
598        } 
599        BDBG_ASSERT(acc->count<acc->nvecs);
600        acc->vec[acc->count] = *vec;
601        acc->owner[acc->count] = NULL;
602        acc->length += vec->len;
603        acc->count++;
604        BDBG_MSG_TRACE(("batom_accum_add_vec: <%#lx %#lx[%#lx:%u] %u:%u", (unsigned long)acc, (unsigned long)vec, (unsigned long)vec->base, vec->len, acc->count, acc->nvecs));
605        return;
606}
607
608void 
609batom_accum_add_range(batom_accum_t acc, const void *base, size_t len)
610{
611        batom_vec vec;
612
613        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
614
615    for(;;) {
616        if(len<=BATOM_VEC_MAX_SIZE) {
617        B_ATOM_VEC_INIT(&vec, base, len);
618        batom_accum_add_vec(acc, &vec);
619            break;
620        } else {
621            size_t vec_len =  BATOM_VEC_MAX_SIZE&(~(sizeof(int)-1)); /* don't make unaligned vectors */
622            B_ATOM_VEC_INIT(&vec, base, vec_len);
623            batom_accum_add_vec(acc, &vec);
624            len -= vec_len;
625            base = (uint8_t *)base + vec_len;
626        }
627    }
628        return;
629}
630
631void 
632batom_accum_add_atom(batom_accum_t acc, batom_t atom)
633{
634        unsigned count;
635        const batom_vec *vecs;
636        batom_vec *dst_vecs;
637        batom_t *dst_owners;
638        batom_t master;
639        unsigned acc_count;
640        unsigned acc_nvecs;
641        size_t acc_len;
642
643        BDBG_MSG_TRACE(("batom_accum_add_atom: >%#lx %#lx", (unsigned long)acc, (unsigned long)atom));
644        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
645        BDBG_ASSERT(atom);
646        BDBG_OBJECT_ASSERT(acc->factory, batom_factory_t);
647        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
648        master = B_ATOM_MASTER(atom);
649        BDBG_OBJECT_ASSERT(master->factory, batom_factory_t);
650        vecs = B_ATOM_VEC_PTR_ARRAY(master);
651        count = master->u.array.count;
652#if 0
653        if(count==1 && acc->count < acc->nvecs) {
654                acc->owner[acc->count] = *owners;
655                acc->vec[acc->count] = *vecs;
656                acc->count++;
657                BDBG_ASSERT(atom->ref_cnt<BATOM_VEC_MAX_SIZE);
658                atom->ref_cnt++;
659                return;
660        }
661#endif
662        BDBG_ASSERT(acc->count<=acc->nvecs);
663        /* temporary variables used to reduce number of memory loads */
664        acc_count = acc->count;
665        acc_nvecs = acc->nvecs;
666        acc_len = acc->length;
667        dst_owners = &acc->owner[acc_count];
668        dst_vecs = &acc->vec[acc_count];
669        for(acc_count=acc->count;count;) {
670                /* code alligned in this fashion, to short-circuit most likely case (no grow) */
671                if (acc_count < acc_nvecs) {
672                        b_atom_lock(atom);
673                        *dst_owners = atom;
674                        acc_len += vecs->len;
675                        *dst_vecs = *vecs;
676                        dst_owners++;
677                        vecs++;
678                        dst_vecs++;
679                        acc_count++;
680                        count--;
681                        continue;
682                }
683                acc->count = acc_count;
684                acc->length = acc_len;
685                if(!b_io_acc_grow(acc)) {
686                        break;
687                }
688                /* reload pointers they may changed */
689                dst_owners = &acc->owner[acc_count];
690                dst_vecs = &acc->vec[acc_count];
691                acc_nvecs = acc->nvecs;
692                BDBG_ASSERT(acc->count==acc_count);
693                BDBG_ASSERT(acc->count<acc->nvecs);
694        }
695        acc->length = acc_len;
696        acc->count = acc_count;
697        BDBG_MSG_TRACE(("batom_accum_add_acc: <%#lx %u:%u", (unsigned long)acc, acc_len, acc_count));
698        return;
699}
700
701
702void 
703batom_accum_trim(batom_accum_t acc, batom_cursor *cursor)
704{
705        unsigned i;
706        unsigned trim_pos;
707
708        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
709        BDBG_ASSERT(cursor->vec == acc->vec);
710        BDBG_ASSERT(cursor->count == acc->count);
711        BDBG_ASSERT(cursor->pos <=  cursor->count);
712        BDBG_ASSERT(acc->nvecs  >= acc->count);
713        BDBG_MSG_TRACE(("batom_accum_trim<:%#lx %u %u  cursor: %#lx %u %d", (unsigned long)acc, acc->count, acc->length, (unsigned long)cursor, cursor->pos, cursor->left));
714
715        if (cursor->left > 0) {
716                trim_pos = cursor->pos-1;
717        } else {
718                trim_pos = cursor->pos;
719        }
720        if(trim_pos>0) {
721                batom_vec *vec = acc->vec;
722                batom_t  *owner = acc->owner;
723                size_t count;
724
725                BDBG_ASSERT(acc->count >= trim_pos);
726                /* remove dead entries */
727                for(count=0,i=0;i<trim_pos;i++) {
728                        if(*owner) {
729                                batom_release(*owner);
730                        }
731                        count += vec->len;
732                        owner++;
733                        vec++;
734                }
735                BDBG_ASSERT(acc->length >= count);
736                acc->length -= count;
737                vec = acc->vec;
738                owner = acc->owner;
739                count = acc->count;
740                for(i=0;i+trim_pos<count;i++) {
741                        *vec = vec[trim_pos];
742                        *owner = owner[trim_pos];
743                        vec++;
744                        owner++;
745                }
746                acc->count = count - trim_pos;
747        }
748        if (cursor->left > 0) {
749                /* adjust for the partial vector */
750                BDBG_ASSERT(acc->vec[0].len >=cursor->left); 
751                BDBG_ASSERT(acc->length >= (acc->vec[0].len - (unsigned)cursor->left)); 
752                acc->length -= acc->vec[0].len - cursor->left;
753                acc->vec[0].base = (void *)cursor->cursor;
754                acc->vec[0].len = cursor->left;
755        }
756        /* adjust cursor */
757        cursor->pos = 0;
758        cursor->left = 0;
759        cursor->cursor = 0;
760    cursor->count = acc->count;
761        BDBG_MSG_TRACE(("batom_accum_trim<: %#lx %u %u", (unsigned long)acc, acc->count, acc->length));
762        return ;
763}
764
765static batom_t
766b_atom_alloc(batom_factory_t factory, size_t atom_size)
767{
768        batom_t atom;
769
770        if (atom_size<=B_ATOM_INIT_SIZE) {
771                atom = bpool_alloc(factory->pool, B_ATOM_INIT_SIZE);
772                if(atom) {
773                        factory->stats.alloc_pool++;
774                        atom->alloc_type = B_ATOM_ALLOC_POOL;
775                        goto done;
776                }
777                factory->stats.full_pool++;
778        }
779        atom = barena_alloc(factory->arena, atom_size);
780        if (atom) {
781                factory->stats.alloc_arena++;
782                atom->alloc_type = B_ATOM_ALLOC_ARENA;
783                goto done;
784        } 
785#if 0
786        barena_dump(factory->arena);
787        BDBG_ERR(("%u:%u:%u:%u %u:%u:%u", atom_size, B_ATOM_INIT_SIZE, factory->stats.full_pool, factory->stats.alloc_pool-factory->stats.free_pool, factory->stats.alloc_arena, factory->stats.alloc_arena-factory->stats.free_arena, factory->stats.full_arena));
788        getchar();
789#endif
790        factory->stats.full_arena++;
791        atom = factory->alloc->bmem_alloc(factory->alloc, atom_size);
792        if (atom) {
793                factory->stats.alloc_alloc++;
794                atom->alloc_type = B_ATOM_ALLOC_ALLOC;
795                goto done;
796        }
797        BDBG_ASSERT(0);
798done:
799        BDBG_MSG_TRACE(("b_atom_alloc: %#lx", (unsigned long)atom));
800        return atom;
801}
802
803
804static void
805b_atom_init(batom_factory_t factory, batom_t atom, unsigned count, unsigned type, const batom_user  *user, const void *udata)
806{
807        void * atom_user_ptr;
808
809        atom->factory = factory;
810        atom->ref_cnt = 1;
811        atom->atom_type = type;
812        atom->ops = user;
813        BLST_SQ_NEXT(atom,pipe_link) = NULL;
814        factory->stats.atom_live++;
815        factory->stats.atom_allocated++;
816        if(type==B_ATOM_TYPE_ARRAY) {
817                atom->u.array.count = count;
818        }
819        atom_user_ptr = B_ATOM_USER_PTR(atom);
820        if(user->user_size==sizeof (void *)) {
821                BDBG_ASSERT(udata);
822                *(void **) atom_user_ptr = *(void **)udata;
823        } else if(user->user_size==2*sizeof (unsigned)) {
824                BDBG_ASSERT(udata);
825                ((unsigned *)atom_user_ptr)[0] = ((unsigned *)udata)[0];
826                ((unsigned *)atom_user_ptr)[1] = ((unsigned *)udata)[1];
827        } else {
828                BDBG_ASSERT(udata || user->user_size==0);
829                BKNI_Memcpy(atom_user_ptr, udata, user->user_size);
830        }
831        return;
832}
833
834static batom_t
835b_atom_create(batom_factory_t factory, unsigned count, unsigned type, const batom_user *user, const void *udata)
836{
837        batom_t atom;
838        size_t atom_size;
839
840        if (user==NULL) {
841                user = &b_atom_default_ops;
842        }
843        atom_size = user->user_size + sizeof(*atom) + count*(sizeof(batom_vec)+sizeof(batom_t));
844        atom = b_atom_alloc(factory, atom_size);
845        if(atom) {
846                b_atom_init(factory, atom, count, type, user, udata);
847        }
848        return atom;
849}
850               
851batom_t
852batom_from_vector(batom_factory_t factory, const batom_vec *vec, const batom_user  *user, const void *udata)
853{
854        batom_t atom;
855        batom_vec *vecs;
856        batom_t *owners;
857
858        BDBG_ASSERT(vec);
859        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
860        atom = b_atom_create(factory, 1, B_ATOM_TYPE_ARRAY, user, udata);
861        if (!atom) {
862                goto done;
863        }
864        atom->u.array.length = vec->len;
865        vecs = B_ATOM_VEC_PTR_ARRAY(atom);
866        owners = B_ATOM_PTR_ARRAY(atom);
867        *vecs = *vec;
868        *owners = atom;
869done:
870        return atom;
871}
872
873
874static void
875b_atom_copy_vecs(batom_vec *dst, const batom_vec *src, unsigned count)
876{
877        for(;count>0;count--) {
878                *dst++ = *src++;
879        }
880        return;
881}
882
883
884static void
885b_atom_copy_vecs_copy_owners(batom_vec *v_dst, const batom_vec *v_src, batom_t *o_dst, const batom_t *o_src, unsigned count, batom_t owner)
886{
887        for(;count>0;count--) {
888                batom_t s_atom = *o_src++;
889                if(s_atom==NULL) {
890                        s_atom = owner;
891                }
892                *o_dst++ = s_atom;
893                *v_dst++ = *v_src++;
894        }
895        return;
896}
897
898static void
899b_atom_copy_vecs_use_owners(batom_vec *v_dst, const batom_vec *v_src, batom_t *o_dst, const batom_t *o_src, unsigned count, batom_t owner)
900{
901        for(;count>0;o_src++,o_dst++,count--) {
902                batom_t atom = *o_src;
903                if(atom!=NULL) {
904                        b_atom_lock(atom);
905                        *o_dst = atom;
906                } else {
907                        *o_dst = owner;
908                }
909                *v_dst++ = *v_src++;
910        }
911        return;
912}
913
914
915batom_t
916batom_from_vectors(batom_factory_t factory, const batom_vec *vec, unsigned nvecs, const batom_user  *user, const void *udata)
917{
918        batom_t atom;
919        batom_vec *vecs;
920        batom_t *owners;
921        unsigned i;
922
923        BDBG_ASSERT(vec);
924        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
925        atom = b_atom_create(factory, nvecs, B_ATOM_TYPE_ARRAY, user, udata);
926        if (!atom) {
927                goto done;
928        }
929        vecs = B_ATOM_VEC_PTR_ARRAY(atom);
930        owners = B_ATOM_PTR_ARRAY(atom);
931        atom->u.array.length = 0;
932        for(i=0;i<nvecs;i++) {
933                atom->u.array.length += vec[i].len;
934                owners[i] = atom;
935        }
936        b_atom_copy_vecs(vecs, vec, nvecs);
937done:
938        return atom;
939}
940
941/* limit size to BATOM_VEC_MAX_SIZE*24 =  1572840 bytes , to handle MP4/MKV streams this should be as large as largest frame in the stream */
942#define BATOM_MAX_VECTORS       24
943
944batom_t
945batom_from_range(batom_factory_t factory, const void *base, size_t len, const batom_user  *user, const void *udata)
946{
947        batom_vec vec[BATOM_MAX_VECTORS];
948        batom_t atom;
949        BDBG_MSG_TRACE(("batom_from_range>: %#lx %#lx %u", (unsigned long)factory, (unsigned long)base, len));
950        if(len<=BATOM_VEC_MAX_SIZE) {
951                B_ATOM_VEC_INIT(&vec[0], base, len);
952                atom = batom_from_vector(factory, &vec[0], user, udata);
953        } else {
954                unsigned count = 0;
955                for(count=0;len>0;count++) {
956                        unsigned size = BATOM_VEC_MAX_SIZE&(~(sizeof(int)-1)); /* don't make unaligned vectors */
957                        if(count>=BATOM_MAX_VECTORS) {
958                                BDBG_ERR(("batom_from_range: size of the %u range exceededs %u:(%u:%u)", len+(BATOM_MAX_VECTORS*size), BATOM_MAX_VECTORS*size, count, BATOM_MAX_VECTORS));
959                                return NULL;
960                        }
961                        if(size>len) {
962                                size = len;
963                        }
964                        len -= size;
965                        B_ATOM_VEC_INIT(&vec[count], base, size);
966                        base = (uint8_t *)base + size;
967                }
968                atom = batom_from_vectors(factory, vec, count, user, udata);
969        }
970        BDBG_MSG_TRACE(("batom_from_range<: %#lx -> %#lx", (unsigned long)factory, (unsigned long)atom));
971        return atom;
972}
973
974batom_t
975batom_empty(batom_factory_t factory, const batom_user *user, const void *udata)
976{
977        batom_t atom;
978
979        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
980        atom = b_atom_create(factory, 0, B_ATOM_TYPE_ARRAY, user, udata);
981        if (!atom) {
982                goto done;
983        }
984        atom->u.array.length = 0;
985done:
986        return atom;
987}
988
989batom_t
990batom_from_vec_and_atom(const batom_vec *vec, batom_t atom, const batom_user  *user, const void *udata)
991{
992        batom_factory_t factory;
993        batom_t master;
994        unsigned acc_count;
995
996        BDBG_MSG_TRACE(("batom_from_vec_and_atom>: %#lx %#lx", (unsigned long)vec, (unsigned long)atom));
997        BDBG_ASSERT(vec);
998        BDBG_ASSERT(atom);
999        factory = atom->factory;
1000        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
1001        master = B_ATOM_MASTER(atom);
1002        acc_count = master->u.array.count+1;
1003        atom = b_atom_create(factory, acc_count, B_ATOM_TYPE_ARRAY, user, udata);
1004        if (atom) {
1005                batom_vec *vecs = B_ATOM_VEC_PTR_ARRAY(atom);
1006                batom_t *owners = B_ATOM_PTR_ARRAY(atom);
1007                atom->u.array.length = master->u.array.length+vec->len;
1008                *vecs = *vec;
1009                *owners = atom;
1010                b_atom_copy_vecs_use_owners(vecs+1, B_ATOM_VEC_PTR_ARRAY(master), owners+1, B_ATOM_PTR_ARRAY(master), acc_count-1, atom);
1011        }
1012        BDBG_MSG_TRACE(("batom_from_vec_and_atom<: %#lx %#lx -> %#lx", (unsigned long)vec, (unsigned long)master, (unsigned long)atom));
1013        return atom;
1014}
1015
1016batom_t
1017batom_from_range_and_atom(const void *base, size_t len, batom_t atom, const batom_user  *user, const void *udata)
1018{
1019        batom_vec vec;
1020
1021        BDBG_ASSERT(len<=BATOM_VEC_MAX_SIZE);
1022
1023        B_ATOM_VEC_INIT(&vec, base, len);
1024        return batom_from_vec_and_atom(&vec, atom, user, udata);
1025}
1026
1027batom_t
1028batom_from_accum(batom_accum_t acc, const batom_user  *user, const void *udata)
1029{
1030        batom_t atom;
1031        batom_factory_t factory;
1032        unsigned acc_count;
1033
1034        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
1035        factory = acc->factory;
1036        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
1037
1038        acc_count = acc->count;
1039        atom = b_atom_create(factory, acc_count, B_ATOM_TYPE_ARRAY, user, udata);
1040        if (atom) {
1041                atom->u.array.length = acc->length;
1042                b_atom_copy_vecs_copy_owners(B_ATOM_VEC_PTR_ARRAY(atom), acc->vec, B_ATOM_PTR_ARRAY(atom), acc->owner, acc_count, atom);
1043                BDBG_MSG_TRACE(("batom_from_accum: %#lx -> %#lx (%u:%u)", (unsigned long)acc, (unsigned long)atom, atom->u.array.length, atom->u.array.count));
1044        }
1045        acc->count = 0;
1046        acc->length = 0;
1047        return atom;
1048}
1049
1050batom_t
1051batom_accum_extract(batom_accum_t acc, const batom_cursor *first, const batom_cursor *last, const batom_user  *user, const void *udata)
1052{
1053        batom_t atom;
1054        batom_factory_t factory;
1055        unsigned nvecs;
1056        unsigned first_pos;
1057
1058        BDBG_MSG_TRACE(("batom_accum_extract>: %#lx %#lx %#lx %#lx %#lx", (unsigned long)acc, (unsigned long)first, (unsigned long)last, (unsigned long)user, (unsigned long)udata));
1059        BDBG_OBJECT_ASSERT(acc, batom_accum_t);
1060        BDBG_ASSERT(first->vec == acc->vec);
1061        BDBG_ASSERT(first->count == acc->count);
1062        BDBG_ASSERT(first->pos <=  first->count);
1063        BDBG_ASSERT(last->vec == acc->vec);
1064        BDBG_ASSERT(last->count == acc->count);
1065        BDBG_ASSERT(last->pos <=  last->count);
1066        BDBG_ASSERT(acc->nvecs >= acc->count);
1067        BDBG_ASSERT(first->pos <= last->pos);
1068        BDBG_ASSERT(batom_cursor_pos(first) <= batom_cursor_pos(last));
1069
1070        factory = acc->factory;
1071        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
1072
1073        BDBG_MSG_TRACE(("batom_accum_extract: %#lx %u..%u %#lx[%u]", (unsigned long)acc, batom_cursor_pos(first), batom_cursor_pos(last), (unsigned long)user, user?user->user_size:0));
1074        if(first->left>0) {
1075                first_pos = first->pos - 1;
1076        } else {
1077                first_pos = first->pos;
1078        }       
1079        BDBG_ASSERT(last->pos>=first_pos);
1080        nvecs = last->pos - first_pos;
1081
1082        atom = b_atom_create(factory, nvecs, B_ATOM_TYPE_ARRAY, user, udata);
1083        if (atom) {
1084                atom->u.array.length = batom_cursor_pos(last) - batom_cursor_pos(first);
1085                if (nvecs>0) {
1086                        batom_vec *vecs = B_ATOM_VEC_PTR_ARRAY(atom);
1087                        /* copy vectors */
1088
1089                        b_atom_copy_vecs_use_owners(vecs, acc->vec+first_pos, B_ATOM_PTR_ARRAY(atom), acc->owner+first_pos, nvecs, atom);
1090                        /* adjust first vector */
1091                        if(first->left > 0) {
1092                                BDBG_ASSERT(acc->vec[first_pos].len>= first->left);
1093                                vecs[0].len = first->left;
1094                                vecs[0].base = (uint8_t *)vecs[0].base + (acc->vec[first_pos].len - first->left);
1095                        }
1096                        /* adjust last vector */
1097                        if(last->left > 0) {
1098                                BDBG_ASSERT(vecs[nvecs-1].len >= last->left);
1099                                vecs[nvecs-1].len -= last->left;
1100                        }
1101                        BDBG_MSG_TRACE(("batom_accum_extract: %#lx -> %#lx (%u:%u) %#lx:%u", (unsigned long)acc, (unsigned long)atom, atom->u.array.length, atom->u.array.count, (unsigned long)vecs[0].base, vecs[0].len));
1102                } /* else nvecs = 0, do nothing */
1103        }
1104        BDBG_MSG_TRACE(("batom_accum_extract<: %#lx %#lx(%u)", (unsigned long)acc, (unsigned long)atom, atom?atom->u.array.length:0));
1105        return atom;
1106}
1107
1108bool
1109batom_accum_append(batom_accum_t dst, batom_accum_t src, const batom_cursor *first, const batom_cursor *last)
1110{
1111        batom_factory_t factory;
1112        unsigned nvecs;
1113        unsigned first_pos;
1114        unsigned dst_pos;
1115
1116        BDBG_MSG_TRACE(("batom_accum_copy>: %#lx<-%lx %#lx %#lx %#lx", (unsigned long)dst, (unsigned long)src, (unsigned long)first, (unsigned long)last));
1117        BDBG_OBJECT_ASSERT(dst, batom_accum_t);
1118        BDBG_OBJECT_ASSERT(src, batom_accum_t);
1119        BDBG_ASSERT(first->vec == src->vec);
1120        BDBG_ASSERT(first->count == src->count);
1121        BDBG_ASSERT(first->pos <=  first->count);
1122        BDBG_ASSERT(last->vec == src->vec);
1123        BDBG_ASSERT(last->count == src->count);
1124        BDBG_ASSERT(last->pos <=  last->count);
1125        BDBG_ASSERT(src->nvecs >= src->count);
1126        BDBG_ASSERT(dst->nvecs >= dst->count);
1127        BDBG_ASSERT(first->pos <= last->pos);
1128        BDBG_ASSERT(batom_cursor_pos(first) <= batom_cursor_pos(last));
1129
1130        factory = dst->factory;
1131        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
1132
1133        BDBG_MSG_TRACE(("batom_accum_copy: %#lx->%lx %u..%u", (unsigned long)src, (unsigned long)dst, batom_cursor_pos(first), batom_cursor_pos(last)));
1134        if(first->left>0) {
1135                first_pos = first->pos - 1;
1136        } else {
1137                first_pos = first->pos;
1138        }
1139        BDBG_ASSERT(last->pos>=first_pos);
1140        nvecs = last->pos - first_pos;
1141        while(dst->count+nvecs >= dst->nvecs) {
1142                /* grow until it has enough space */
1143                dst_pos = dst->nvecs;
1144                if(!b_io_acc_grow(dst)) {
1145                        return false;
1146                }
1147                BDBG_ASSERT(dst->nvecs>dst_pos); /* test that loop eventually terminates */
1148        } 
1149        dst->length += batom_cursor_pos(last) - batom_cursor_pos(first);
1150        if (nvecs>0) {
1151                batom_vec *vecs; /* pointer to the vector table */
1152                dst_pos = dst->count;
1153                dst->count += nvecs;
1154                vecs = &dst->vec[dst_pos];
1155                /* copy vectors */
1156                b_atom_copy_vecs_use_owners(vecs, src->vec+first_pos, dst->owner+dst_pos, src->owner+first_pos, nvecs, NULL);
1157                /* adjust first vector */
1158                if(first->left > 0) {
1159                        BDBG_ASSERT(src->vec[first_pos].len>= first->left);
1160                        vecs[0].len = first->left;
1161                        vecs[0].base = (uint8_t *)vecs[0].base + (src->vec[first_pos].len - first->left);
1162                }
1163                /* adjust last vector */
1164                if(last->left > 0) {
1165                        BDBG_ASSERT(vecs[nvecs-1].len >= last->left);
1166                        vecs[nvecs-1].len -= last->left;
1167                }
1168                BDBG_MSG_TRACE(("batom_accum_copy: %#lx <- %#lx (%u(%u):%u) %#lx:%u", (unsigned long)dst, (unsigned long)src, dst->length, batom_cursor_pos(last) - batom_cursor_pos(first), nvecs, (unsigned long)vecs[0].base, vecs[0].len));
1169        } /* else nvecs = 0, do nothing */
1170        BDBG_MSG_TRACE(("batom_accum_copy<: %#lx %#lx(%u) %u:%u", (unsigned long)dst, (unsigned long)src, dst->length, dst->nvecs, dst->count, dst->nvecs));
1171        return true;
1172}
1173
1174batom_t
1175batom_extract(batom_t src, const batom_cursor *first, const batom_cursor *last, const batom_user  *user, const void *udata)
1176{
1177        batom_t atom;
1178        batom_t master;
1179        batom_factory_t factory;
1180        unsigned nvecs;
1181        unsigned first_pos;
1182
1183        BDBG_MSG_TRACE(("batom_extract>: %#lx %#lx %#lx %#lx %#lx", (unsigned long)src, (unsigned long)first, (unsigned long)last, (unsigned long)user, (unsigned long)udata));
1184        BDBG_ASSERT(src);
1185
1186        master = B_ATOM_MASTER(src);
1187        BDBG_ASSERT(master);
1188        factory = src->factory;
1189        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
1190
1191        BDBG_ASSERT(first->vec == B_ATOM_VEC_PTR_ARRAY(master));
1192        BDBG_ASSERT(first->count == master->u.array.count);
1193        BDBG_ASSERT(first->pos <=  first->count);
1194        BDBG_ASSERT(last->vec == B_ATOM_VEC_PTR_ARRAY(master));
1195        BDBG_ASSERT(last->count == master->u.array.count);
1196        BDBG_ASSERT(last->pos <=  last->count);
1197        BDBG_ASSERT(first->pos <= last->pos);
1198        BDBG_ASSERT(batom_cursor_pos(first) <= batom_cursor_pos(last));
1199
1200        BDBG_MSG_TRACE(("batom_accum_extract: %#lx %u..%u %#lx[%u]", (unsigned long)src, batom_cursor_pos(first), batom_cursor_pos(last), (unsigned long)user, user?user->user_size:0));
1201        if(first->left>0) {
1202                first_pos = first->pos - 1;
1203        } else {
1204                first_pos = first->pos;
1205        }       
1206        BDBG_ASSERT(last->pos>=first_pos);
1207        nvecs = last->pos - first_pos;
1208
1209        atom = b_atom_create(factory, nvecs, B_ATOM_TYPE_ARRAY, user, udata);
1210        if (atom) {
1211                atom->u.array.length = batom_cursor_pos(last) - batom_cursor_pos(first);
1212                if (nvecs>0) {
1213                        const batom_vec *svecs = B_ATOM_VEC_PTR_ARRAY(master);
1214                        batom_vec *vecs = B_ATOM_VEC_PTR_ARRAY(atom);
1215                        /* copy vectors */
1216
1217                        b_atom_copy_vecs_use_owners(vecs, svecs+first_pos, B_ATOM_PTR_ARRAY(atom), B_ATOM_PTR_ARRAY(master)+first_pos, nvecs, atom);
1218                        /* adjust first vector */
1219                        if(first->left > 0) {
1220                                BDBG_ASSERT(svecs[first_pos].len>= first->left);
1221                                vecs[0].len = first->left;
1222                                vecs[0].base = (uint8_t *)vecs[0].base + (svecs[first_pos].len - first->left);
1223                        }
1224                        /* adjust last vector */
1225                        if(last->left > 0) {
1226                                BDBG_ASSERT(vecs[nvecs-1].len >= last->left);
1227                                vecs[nvecs-1].len -= last->left;
1228                        }
1229                        BDBG_MSG_TRACE(("batom_accum_extract: %#lx -> %#lx (%u:%u) %#lx:%u", (unsigned long)src, (unsigned long)atom, atom->u.array.length, atom->u.array.count, (unsigned long)vecs[0].base, vecs[0].len));
1230                } /* else nvevcs = 0, do nothing */
1231        }
1232        BDBG_MSG_TRACE(("batom_accum_extract<: %#lx %#lx(%u)", (unsigned long)src, (unsigned long)atom, atom?atom->u.array.length:0));
1233        return atom;
1234}
1235
1236batom_t
1237batom_clone(batom_t atom, const batom_user  *user, const void *udata)
1238{
1239        batom_t clone;
1240        batom_factory_t factory;
1241        BDBG_ASSERT(atom);
1242
1243
1244        BDBG_MSG_TRACE(("batom_clone>: %#lx", (unsigned long)atom));
1245        factory = atom->factory;
1246        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
1247
1248        clone = b_atom_create(factory, 0, B_ATOM_TYPE_CLONE, user, udata);
1249        if(clone) {
1250                b_atom_lock(atom);
1251                clone->u.clone.parent = atom;
1252                clone->u.clone.master = B_ATOM_MASTER(atom);
1253        }
1254        BDBG_MSG_TRACE(("batom_clone<: %#lx -> %#lx", (unsigned long)atom, (unsigned long)clone));
1255        return clone;
1256}
1257
1258
1259size_t 
1260batom_len(batom_t atom)
1261{
1262        batom_t master;
1263
1264        BDBG_MSG_TRACE(("batom_len: >%#lx", (unsigned long)atom));
1265        BDBG_ASSERT(atom);
1266        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
1267        master = B_ATOM_MASTER(atom);
1268        BDBG_OBJECT_ASSERT(master->factory, batom_factory_t);
1269        BDBG_MSG_TRACE(("batom_len: <%#lx %u", (unsigned long)atom, master->u.array.length));
1270        return master->u.array.length;
1271}
1272
1273const batom_vec *
1274batom_get_vectors(batom_t atom, unsigned *nvecs)
1275{
1276        batom_t master;
1277
1278        BDBG_ASSERT(atom);
1279        BDBG_ASSERT(nvecs);
1280        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
1281        master = B_ATOM_MASTER(atom);
1282        BDBG_ASSERT(master);
1283        *nvecs = master->u.array.count;
1284        BDBG_OBJECT_ASSERT(master->factory, batom_factory_t);
1285        return B_ATOM_VEC_PTR_ARRAY(master);
1286}
1287
1288const batom_vec *
1289batom_get_vec(batom_t atom, unsigned vecno)
1290{
1291        batom_t master;
1292
1293        BDBG_ASSERT(atom);
1294        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
1295        master = B_ATOM_MASTER(atom);
1296        BDBG_ASSERT(master);
1297        BDBG_OBJECT_ASSERT(master->factory, batom_factory_t);
1298        if(vecno<master->u.array.count) {
1299                return B_ATOM_VEC_PTR_ARRAY(master)+vecno;
1300        } 
1301        return NULL;
1302}
1303
1304unsigned 
1305batom_get_nvecs(batom_t atom)
1306{
1307        batom_t master;
1308
1309        BDBG_ASSERT(atom);
1310        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
1311        master = B_ATOM_MASTER(atom);
1312        BDBG_ASSERT(master);
1313        BDBG_OBJECT_ASSERT(master->factory, batom_factory_t);
1314        return master->u.array.count;
1315}
1316
1317void *
1318batom_userdata(batom_t atom)
1319{
1320        BDBG_MSG_TRACE(("batom_userdata: >%#lx", (unsigned long)atom));
1321        BDBG_ASSERT(atom);
1322        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
1323        if(atom->ops->user_size) {
1324                BDBG_MSG_TRACE(("batom_userdata: <%#lx %#lx %#lx", (unsigned long)atom, (unsigned long)B_ATOM_USER_PTR(atom), *(unsigned long*)B_ATOM_USER_PTR(atom)));
1325                return B_ATOM_USER_PTR(atom); 
1326        } else {
1327                BDBG_MSG_TRACE(("batom_userdata: <%#lx NULL", (unsigned long)atom));
1328                return NULL;
1329        }
1330}
1331
1332
1333static size_t 
1334b_atom_cursor_refill(batom_cursor *cursor)
1335{
1336
1337        BDBG_ASSERT(cursor->left<=0);
1338        if (cursor->left==0) {
1339                unsigned pos;
1340                const batom_vec *vec;
1341                BDBG_ASSERT(cursor->vec);
1342                BDBG_ASSERT(cursor->pos <= cursor->count);
1343                for(pos=cursor->pos,vec=&cursor->vec[pos];pos < cursor->count;vec++) {
1344                        pos++;
1345                        cursor->pos = pos;
1346                        if (vec->len>0) {
1347                                cursor->left = vec->len;
1348                                cursor->cursor = vec->base;
1349                                BDBG_MSG_TRACE(("b_atom_cursor_refill: %#lx %u:%u %u %#lx", (unsigned long)cursor, cursor->pos, cursor->count, cursor->left, (unsigned long)cursor->cursor));
1350                                return (size_t)cursor->left;
1351                        }
1352                }
1353                /* (pos >= cursor->count)  */
1354                BDBG_MSG_TRACE(("b_atom_cursor_refill: %#lx %u %u EOF", (unsigned long)cursor, cursor->pos, cursor->count));
1355                /* reached EOF */
1356                cursor->left = BATOM_EOF;
1357        }
1358        return 0;
1359}
1360
1361void 
1362batom_cursor_empty(batom_cursor *cursor)
1363{
1364        BDBG_ASSERT(cursor);
1365        /* empty array */
1366        cursor->left = -1;
1367        cursor->cursor = 0;
1368
1369        cursor->count = 0;
1370        cursor->pos = 0;
1371        cursor->vec = NULL;
1372        return;
1373}
1374
1375
1376void 
1377batom_cursor_from_vec(batom_cursor *cursor, const batom_vec *vec, unsigned count)
1378{
1379        BDBG_ASSERT(cursor);
1380        /* empty array */
1381        cursor->left = 0;
1382        cursor->cursor = 0;
1383
1384        cursor->count = count;
1385        cursor->pos = 0;
1386        cursor->vec = vec;
1387        b_atom_cursor_refill(cursor);
1388        return;
1389}
1390
1391void
1392batom_cursor_from_atom(batom_cursor *cursor, batom_t atom)
1393{
1394        BDBG_ASSERT(cursor);
1395        BDBG_ASSERT(atom);
1396        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
1397        atom = B_ATOM_MASTER(atom);
1398        BDBG_ASSERT(atom);
1399        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
1400        batom_cursor_from_vec(cursor, B_ATOM_VEC_PTR_ARRAY(atom),atom->u.array.count);
1401        return;
1402}
1403
1404void
1405batom_cursor_from_accum(batom_cursor *cursor, batom_accum_t acc)
1406{
1407        BDBG_ASSERT(cursor);
1408        BDBG_ASSERT(acc);
1409        BDBG_OBJECT_ASSERT(acc->factory, batom_factory_t);
1410        batom_cursor_from_vec(cursor, acc->vec, acc->count);
1411        return;
1412}
1413
1414int 
1415batom_cursor_next(batom_cursor *cursor)
1416{
1417        int d;
1418
1419        BDBG_ASSERT(cursor);
1420        while(cursor->left<=0) {
1421                if (b_atom_cursor_refill(cursor)==0) {
1422                        return BATOM_EOF;
1423                }
1424                BDBG_ASSERT(cursor->left>0);
1425        }
1426        d = cursor->cursor[0];
1427        cursor->left--;
1428        cursor->cursor++;
1429        BDBG_MSG_FLOW(("batom_cursor_next: %#lx %d 0x%02x", (unsigned long)cursor, cursor->left, d));
1430        return d;
1431}
1432
1433bool
1434batom_cursor_eof(const batom_cursor *cursor)
1435{
1436        BDBG_ASSERT(cursor);
1437        BDBG_ASSERT(cursor->vec);
1438        BDBG_ASSERT(cursor->pos <= cursor->count);
1439        return cursor->left < 0;
1440}
1441
1442size_t
1443batom_cursor_skip(batom_cursor *cursor, size_t count)
1444{
1445        size_t left;
1446
1447        BDBG_MSG_TRACE(("batom_cursor_skip>: %#lx %d %u", (unsigned long)cursor, cursor->left, count));
1448        count = B_ATOM_TRUNCATE_SIZE(count);
1449        for(left=count;;) {
1450                if (cursor->left>=(int)left) {
1451                        cursor->cursor+=left;
1452                        cursor->left-=left;
1453                        left = 0;
1454                        break;
1455                } 
1456                if (cursor->left>=0) {
1457                        left -= cursor->left;
1458                        cursor->left = 0;
1459                        if (b_atom_cursor_refill(cursor)==0) {
1460                                break;
1461                        }
1462                } else {
1463                        break;
1464                }
1465        }
1466        BDBG_MSG_TRACE(("batom_cursor_skip<: %#lx %d %u %u", (unsigned long)cursor, cursor->left, count, count-left));
1467        return count-left;
1468}
1469
1470size_t
1471batom_cursor_distance(const batom_cursor *from, const batom_cursor *to)
1472{
1473        batom_cursor save;
1474        size_t distance;
1475
1476        BDBG_ASSERT(from);
1477        BDBG_ASSERT(to);
1478        BDBG_ASSERT(from->vec==to->vec);
1479        BDBG_ASSERT(from->pos<=to->pos);
1480
1481        if(from->pos==to->pos && to->left!=BATOM_EOF) {
1482                BDBG_ASSERT(from->left!=BATOM_EOF);
1483                BDBG_ASSERT(from->left >= to->left);
1484                return from->left - to->left;
1485        }
1486        BDBG_ASSERT(from->left!=BATOM_EOF || (from->left==BATOM_EOF && to->left==BATOM_EOF && to->pos==from->pos));
1487        for(distance=0,save = *from; save.pos!=to->pos;) {
1488                distance += save.left;
1489                save.left = 0;
1490                b_atom_cursor_refill(&save);
1491        }
1492        BDBG_ASSERT(save.left >= to->left);
1493        distance += save.left - to->left;
1494        return distance;
1495}
1496
1497size_t 
1498batom_cursor_copy(batom_cursor *cursor, void *dest, size_t count)
1499{
1500        size_t left;
1501
1502        BDBG_ASSERT(cursor);
1503        BDBG_ASSERT((int)count>=0);
1504        BDBG_MSG_TRACE(("batom_cursor_copy>: %#lx %u", (unsigned long)cursor, count));
1505
1506        for(left=count;;) {
1507                const uint8_t *src=cursor->cursor;
1508                int src_left = cursor->left;
1509
1510                if(src_left>=(int)left) {
1511                        cursor->cursor = src+left;
1512                        cursor->left = src_left-left;
1513                        BKNI_Memcpy(dest, src, left);
1514                        left = 0;
1515                        break;
1516                }
1517                if(src_left>=0) {
1518                        cursor->cursor = src+src_left;
1519                        cursor->left = 0;
1520                        left -= src_left;
1521                        BKNI_Memcpy(dest, src, src_left);
1522                        dest = (uint8_t*)dest+src_left;
1523                        if (b_atom_cursor_refill(cursor)==0) {
1524                                break;
1525                        }
1526                } else {
1527                        break;
1528                }
1529        }
1530        return count-left;
1531}
1532
1533int 
1534batom_cursor_compare(const batom_cursor *cursor, const void *buff, size_t count) 
1535{
1536        size_t left;
1537    batom_cursor data;
1538
1539        BDBG_ASSERT(cursor);
1540        BDBG_ASSERT((int)count>=0);
1541        BDBG_MSG_TRACE(("batom_cursor_compare>: %#lx %u", (unsigned long)cursor, count));
1542
1543    BATOM_CLONE(&data, cursor);
1544        for(left=count;;) {
1545                const uint8_t *cursor_data=data.cursor;
1546                int cursor_left = data.left;
1547        int rc;
1548
1549                if(cursor_left>=(int)left) {
1550            /* last block */
1551            rc = BKNI_Memcmp(buff, cursor_data, left);
1552            return rc;
1553                } else if(cursor_left>=0) {
1554                        data.cursor = cursor_data+cursor_left;
1555                        data.left = 0;
1556                        left -= cursor_left;
1557            rc = BKNI_Memcmp(buff, cursor_data, left);
1558            if(rc!=0) {
1559                /* no match */
1560                return rc;
1561            }
1562                        buff = (uint8_t*)buff+cursor_left;
1563                        if (b_atom_cursor_refill(&data)!=0) {
1564                /* some data left in the cursor */
1565                continue;
1566            }
1567        }
1568        break;
1569        }
1570    /* reached end of data */
1571    return -1;
1572}
1573
1574void 
1575batom_cursor_save(const batom_cursor *cursor, batom_checkpoint *checkpoint)
1576{
1577        BDBG_MSG_TRACE(("batom_cursor_save: %#lx", (unsigned long)cursor));
1578        checkpoint->cp_left = cursor->left;
1579        checkpoint->cp_pos = cursor->pos;
1580        return;
1581}
1582
1583void 
1584batom_cursor_rollback(batom_cursor *cursor, const batom_checkpoint *checkpoint)
1585{
1586        BDBG_MSG_TRACE(("batom_cursor_rollback: %#lx(%d:%u) %lx(%d:%u)", (unsigned long)cursor, cursor->left, cursor->pos, (unsigned long)checkpoint, checkpoint->cp_left, checkpoint->cp_pos));
1587        BDBG_ASSERT( cursor->pos >= checkpoint->cp_pos );
1588        cursor->left = checkpoint->cp_left;
1589        cursor->pos = checkpoint->cp_pos;
1590        if (cursor->left>0) {
1591                BDBG_ASSERT(cursor->vec);
1592                BDBG_ASSERT(cursor->pos <= cursor->count && cursor->pos>0);
1593                BDBG_ASSERT(cursor->left <= (int)cursor->vec[cursor->pos-1].len);
1594                cursor->cursor = cursor->vec[cursor->pos-1].base;
1595                cursor->cursor += cursor->vec[cursor->pos-1].len - cursor->left;
1596                BDBG_MSG_TRACE(("batom_cursor_rollback: %#lx(%d:%u:%#lx)", (unsigned long)cursor, cursor->left, cursor->pos, (unsigned long)cursor->cursor));
1597        } else {
1598                BDBG_MSG_TRACE(("batom_cursor_rollback: %#lx %u %u EOF", (unsigned long)cursor, cursor->pos, cursor->count));
1599                return;
1600        }
1601        return;
1602}
1603
1604size_t 
1605batom_cursor_pos(const batom_cursor *cursor)
1606{
1607        size_t i;
1608        size_t size;
1609
1610        /* count completed iovec's */
1611        for(size=0,i=0;i<cursor->pos;i++) {
1612                size += cursor->vec[i].len;
1613        }
1614        /* add current iovec */
1615        if (cursor->left>0) {
1616                size -= cursor->left;
1617        }
1618        BDBG_MSG_TRACE(("batom_cursor_pos: %#lx %u", (unsigned long)cursor, size));
1619        return size;
1620}
1621
1622size_t 
1623batom_cursor_size(const batom_cursor *cursor)
1624{
1625        size_t size;
1626        unsigned i;
1627        for(size=0,i=0;i<cursor->count;i++) {
1628                size+=cursor->vec[i].len;
1629        }
1630        return size-batom_cursor_pos(cursor);
1631}
1632
1633size_t
1634batom_cursor_reserve(const batom_cursor *cursor, size_t count)
1635{
1636        batom_cursor save;
1637        BDBG_ASSERT(cursor);
1638        BDBG_MSG_TRACE(("bio_cursor_reserve+: %#lx(%d,%u) %u", (unsigned long)cursor, cursor->left, cursor->pos, count));
1639
1640        BDBG_ASSERT(count == B_ATOM_TRUNCATE_SIZE(count)); /* fast versuib BATOM_RESERVE doesn't mask msb, so make slow version to fail */
1641        if(cursor->left > (int)count) {
1642                return count; /* short circuit */
1643        }
1644
1645    BATOM_CLONE(&save,cursor);
1646
1647        return batom_cursor_skip(&save, count);
1648}
1649
1650void 
1651batom_cursor_clone(batom_cursor *dst, const batom_cursor *src) 
1652{
1653        BDBG_ASSERT(dst);
1654        BDBG_ASSERT(src);
1655        /* do a plain copy */
1656        *dst = *src;
1657        return;
1658}
1659
1660uint8_t
1661batom_cursor_byte(batom_cursor *c)
1662{
1663        uint8_t d;
1664        if (c->left>0) {
1665                d = c->cursor[0];
1666                c->left--;
1667                c->cursor++;
1668        }  else {
1669                if (b_atom_cursor_refill(c)==0) {
1670                        return (uint8_t)BATOM_EOF;
1671                }
1672                BDBG_ASSERT(c->left>0);
1673                d = c->cursor[0];
1674                c->left--;
1675                c->cursor++;
1676        }
1677        return d;
1678}
1679
1680uint32_t 
1681batom_cursor_vword_le(batom_cursor *c, unsigned v)
1682{
1683        uint32_t d;
1684        int c_left;
1685        const uint8_t *c_cursor;
1686        unsigned shift=0;
1687
1688        c_left = c->left;
1689        c_cursor = c->cursor;
1690        for(d=0;v>0;) {
1691                if (c_left>0) {
1692                        d |= ((uint32_t)c_cursor[0])<<shift;
1693                        c_left--;
1694                        c_cursor++;
1695                        v--;
1696                        shift +=8;
1697                        continue;
1698                }  else {
1699                        /* refill cursor */
1700                        c->left = c_left;
1701                        c->cursor = c_cursor;
1702                        if (b_atom_cursor_refill(c)==0) {
1703                                return BATOM_EOF;
1704                        }
1705                        c_left = c->left;
1706                        c_cursor = c->cursor;
1707                }
1708        }
1709        c->left = c_left;
1710        c->cursor = c_cursor;
1711        return d;
1712}
1713
1714uint32_t
1715batom_cursor_vword_be(batom_cursor *c, unsigned v)
1716{
1717        uint32_t d;
1718        int c_left;
1719        const uint8_t *c_cursor;
1720
1721        c_left = c->left;
1722        c_cursor = c->cursor;
1723        for(d=0;v>0;) {
1724                if (c_left>0) {
1725                        d = (d<<8) | ((uint32_t)c_cursor[0]);
1726                        c_left--;
1727                        c_cursor++;
1728                        v--;
1729                        continue;
1730                }  else {
1731                        /* refill cursor */
1732                        c->left = c_left;
1733                        c->cursor = c_cursor;
1734                        if (b_atom_cursor_refill(c)==0) {
1735                                return BATOM_EOF;
1736                        }
1737                        c_left = c->left;
1738                        c_cursor = c->cursor;
1739                }
1740        }
1741        c->left = c_left;
1742        c->cursor = c_cursor;
1743        return d;
1744}
1745
1746
1747
1748uint16_t
1749batom_cursor_uint16_le(batom_cursor *c)
1750{
1751        uint16_t d;
1752        if (c->left>=2) {
1753                d =
1754                                                c->cursor[0] | 
1755                        (((uint16_t)c->cursor[1])<<8);
1756                c->left -= 2;
1757                c->cursor += 2;
1758        } else {
1759                d = batom_cursor_vword_le(c, 2);
1760        }
1761        BDBG_MSG_TRACE(("batom_cursor_uint16_le: %#lx -> 0x%08x", (unsigned long)c, (unsigned)d));
1762        return d;
1763}
1764
1765uint32_t
1766batom_cursor_uint32_le(batom_cursor *c)
1767{
1768        uint32_t d;
1769        if (c->left>=4) {
1770                d =
1771                                                c->cursor[0] |
1772                        (((uint32_t)c->cursor[1])<<8) |
1773                        (((uint32_t)c->cursor[2])<<16) |
1774                        (((uint32_t)c->cursor[3])<<24);
1775                c->left -= 4;
1776                c->cursor += 4;
1777        } else {
1778                d = batom_cursor_vword_le(c, 4);
1779        }
1780        BDBG_MSG_TRACE(("batom_cursor_uint32_le: %#lx -> 0x%08x", (unsigned long)c, (unsigned)d));
1781        return d;
1782}
1783
1784uint16_t
1785batom_cursor_uint16_be(batom_cursor *c)
1786{
1787        uint16_t d;
1788        if (c->left>=2) {
1789                d =
1790                        (((uint16_t)c->cursor[0])<<8) |
1791                                                c->cursor[1];
1792                c->left -= 2;
1793                c->cursor += 2;
1794        } else {
1795                d = batom_cursor_vword_be(c, 2);
1796        }
1797        BDBG_MSG_TRACE(("batom_cursor_uint16_be: %#lx -> 0x%08x", (unsigned long)c, (unsigned)d));
1798        return d;
1799}
1800
1801uint32_t
1802batom_cursor_uint32_be(batom_cursor *c)
1803{
1804        uint32_t d;
1805        if (c->left>=4) {
1806                d =
1807                        (((uint32_t)c->cursor[0])<<24) |
1808                        (((uint32_t)c->cursor[1])<<16) |
1809                        (((uint32_t)c->cursor[2])<<8) |
1810                                                c->cursor[3];
1811                c->left -= 4;
1812                c->cursor += 4;
1813        } else {
1814                d = batom_cursor_vword_be(c, 4);
1815        }
1816        BDBG_MSG_TRACE(("batom_cursor_uint32_le: %#lx -> 0x%08x", (unsigned long)c, (unsigned)d));
1817        return d;
1818}
1819
1820uint64_t 
1821batom_cursor_uint64_le(batom_cursor *c)
1822{
1823        uint64_t d;
1824
1825        d = batom_cursor_uint32_le(c);
1826        d |= ((uint64_t)batom_cursor_uint32_le(c))<<32;
1827        BDBG_MSG_TRACE(("batom_cursor_uint64_le: %#lx -> 0x%16llx", (unsigned long)c, d));
1828        return d;
1829}
1830
1831uint64_t 
1832batom_cursor_uint64_be(batom_cursor *c)
1833{
1834        uint64_t d;
1835
1836        d = ((uint64_t)batom_cursor_uint32_be(c))<<32;
1837        d |= batom_cursor_uint32_be(c);
1838        BDBG_MSG_TRACE(("batom_cursor_uint64_be: %#lx -> 0x%16llx", (unsigned long)c, d));
1839        return d;
1840}
1841
1842uint32_t 
1843batom_cursor_uint24_le(batom_cursor *c)
1844{
1845        uint32_t d;
1846        if (c->left>=3) {
1847                d =
1848                                                c->cursor[0] |
1849                        (((uint32_t)c->cursor[1])<<8) |
1850                        (((uint32_t)c->cursor[2])<<16);
1851                c->left -= 3;
1852                c->cursor += 3;
1853        } else {
1854                d = batom_cursor_vword_le(c, 3);
1855        }
1856        BDBG_MSG_TRACE(("batom_cursor_uint24_le: %#lx -> 0x%08x", (unsigned long)c, (unsigned)d));
1857        return d;
1858}
1859
1860uint32_t 
1861batom_cursor_uint24_be(batom_cursor *c)
1862{
1863        uint32_t d;
1864
1865        if (c->left>=3) {
1866                d =
1867                        (((uint32_t)c->cursor[0])<<16) |
1868                        (((uint32_t)c->cursor[1])<<8) |
1869                                                c->cursor[2];
1870                c->left -= 3;
1871                c->cursor += 3;
1872        } else {
1873                d = batom_cursor_vword_be(c, 3);
1874        }
1875        BDBG_MSG_TRACE(("batom_cursor_uint24_le: %#lx -> 0x%08x", (unsigned long)c, (unsigned)d));
1876        return d;
1877}
1878
1879const void *
1880batom_cursor_continuous(const batom_cursor *c, size_t bytes)
1881{
1882        BDBG_ASSERT(bytes==B_ATOM_TRUNCATE_SIZE(bytes)); /* fast version BATOM_CONTINUOUS doesn't work properly if msb bytes set, so try to detect it here */
1883        if( ( c->left > (int)bytes) /* there is enough bytes in the current segment */
1884                || (c->left >= 0 && c->pos <= c->count && c->left + c->vec[c->pos].len >= (int)bytes && c->cursor+c->left == c->vec[c->pos].base)) /* next vector entry start at the end of current vector and it's they exceed requested size */ {
1885                return c->cursor;
1886        }
1887        return NULL;
1888}
1889
1890
1891void
1892batom_bitstream_init(batom_bitstream *bs, batom_cursor *cursor)
1893{
1894        bs->cursor = cursor;
1895        bs->cache = 0;
1896        bs->cache_pos = -1; /* invalid */
1897}
1898
1899void
1900batom_bitstream_dump(const batom_bitstream *bs)
1901{
1902        BSTD_UNUSED(bs);
1903        BDBG_WRN(("batom_bitstream: cache %08x(%08x) cache_pos %d", bs->cache, (bs->cache << (31-bs->cache_pos)), bs->cache_pos));
1904        return;
1905}
1906
1907bool
1908batom_bitstream_eof(batom_bitstream *bs)
1909{
1910        return bs->cache_pos == -1 && batom_cursor_eof(bs->cursor);
1911}
1912
1913int
1914b_atom_bitstream_refill(batom_bitstream *bs)
1915{
1916        batom_cursor *c = bs->cursor;
1917
1918        BDBG_ASSERT(bs->cache_pos==-1);
1919        if (c->left>=4) {
1920                bs->cache = (uint32_t)c->cursor[3] |
1921                                        ((uint32_t)(c->cursor[2])<<8) |
1922                                        ((uint32_t)(c->cursor[1])<<16) |
1923                                        ((uint32_t)(c->cursor[0])<<24);
1924                bs->cache_pos=31;
1925                c->cursor += 4;
1926                c->left -= 4;
1927                return 0;
1928        } else
1929        {
1930                int next;
1931                uint32_t cache;
1932               
1933                next = batom_cursor_next(c);
1934                if (next==BATOM_EOF) {
1935                        return next;
1936                }
1937                cache = (uint32_t)next;
1938                next = batom_cursor_next(c);
1939                if (next==BATOM_EOF) {
1940                        bs->cache = cache;
1941                        bs->cache_pos = 7; 
1942                        return 0;
1943                }
1944                cache = (cache << 8) | (uint32_t)next;
1945
1946                next = batom_cursor_next(c);
1947                if (next==BATOM_EOF) {
1948                        bs->cache = cache;
1949                        bs->cache_pos = 15; 
1950                        return 0;
1951                }
1952                cache = (cache << 8) | (uint32_t)next;
1953
1954                next = batom_cursor_next(c);
1955                if (next==BATOM_EOF) {
1956                        bs->cache = cache;
1957                        bs->cache_pos = 23; 
1958                        return 0;
1959                }
1960                bs->cache = (cache << 8) | (uint32_t)next;
1961                bs->cache_pos = 31; 
1962                return 0;
1963        }
1964}
1965
1966size_t
1967batom_bitstream_position(const batom_bitstream *bs)
1968{
1969    size_t cursor_pos = batom_cursor_pos(bs->cursor);
1970    return cursor_pos - (bs->cache_pos+1)/8;
1971}
1972
1973size_t 
1974batom_bitstream_bit_position(const batom_bitstream *bs)
1975{
1976    size_t cursor_pos = batom_cursor_pos(bs->cursor);
1977    return (cursor_pos*8) - (bs->cache_pos+1);
1978}
1979
1980int
1981batom_bitstream_show(batom_bitstream *bs)
1982{
1983        int bit;
1984
1985        if(bs->cache_pos==-1) {
1986        if (b_atom_bitstream_refill(bs)==BATOM_EOF) {
1987            return BATOM_EOF;
1988        }
1989        } 
1990        bit = (bs->cache >> bs->cache_pos)&1;
1991        return bit;
1992}
1993
1994int
1995batom_bitstream_bit(batom_bitstream *bs)
1996{
1997        int bit;
1998       
1999        bit = batom_bitstream_show(bs);
2000    bs->cache_pos = bit!=BATOM_EOF ? bs->cache_pos-1:bs->cache_pos;
2001        return bit;
2002}
2003
2004int
2005batom_bitstream_drop(batom_bitstream *bs)
2006{
2007        return batom_bitstream_bit(bs);
2008}
2009
2010unsigned
2011batom_bitstream_bits(batom_bitstream *bs, unsigned nbits)
2012{
2013        uint32_t bits;
2014        int pos;
2015
2016        BDBG_ASSERT(nbits<=31);
2017        BDBG_ASSERT(nbits>0);
2018        pos = bs->cache_pos - nbits;
2019        nbits--;
2020        if( bs->cache_pos>=(int)nbits) {
2021                bits = (bs->cache >> (bs->cache_pos-nbits)) & ((uint32_t)(-1)>>(31-nbits));
2022                bs->cache_pos = pos;
2023                return bits;
2024        } else {
2025                for(bits=0;;) {
2026                        bits |= (unsigned) batom_bitstream_bit(bs);
2027                        if (nbits==0) {
2028                                break;
2029                        }
2030                        nbits--;
2031                        bits <<=1;
2032                }
2033                return bits;
2034        }
2035}
2036
2037void
2038batom_bitstream_drop_bits(struct batom_bitstream *bs, unsigned nbits)
2039{
2040    do {
2041        unsigned to_drop = nbits;
2042        if(to_drop>31) {
2043            to_drop = 31;
2044        }
2045        nbits -= to_drop;
2046            batom_bitstream_bits(bs, to_drop);
2047        if(BATOM_IS_EOF(bs->cursor)) {
2048            break;
2049        }
2050    } while(nbits>0);
2051
2052        return;
2053}
2054
2055batom_pipe_t
2056batom_pipe_create(batom_factory_t factory)
2057{
2058        batom_pipe_t pipe;
2059
2060        BDBG_OBJECT_ASSERT(factory, batom_factory_t);
2061
2062        pipe = factory->alloc->bmem_alloc(factory->alloc, sizeof(*pipe));
2063        if (!pipe) {
2064                goto err_alloc;
2065        }
2066        BDBG_OBJECT_INIT(pipe, batom_pipe_t);
2067        BLST_SQ_INIT(&pipe->atoms);
2068        pipe->push_cnt = 0;
2069        pipe->pop_cnt = 0;
2070        pipe->factory = factory;
2071err_alloc:
2072        return pipe;
2073}
2074
2075
2076void
2077batom_pipe_destroy(batom_pipe_t pipe)
2078{
2079        balloc_iface_t alloc;
2080
2081        BDBG_OBJECT_ASSERT(pipe, batom_pipe_t);
2082        batom_pipe_flush(pipe);
2083        alloc = pipe->factory->alloc;
2084        BDBG_OBJECT_DESTROY(pipe, batom_pipe_t);
2085        alloc->bmem_free(alloc, pipe);
2086        return;
2087}
2088
2089void
2090batom_pipe_push(batom_pipe_t pipe, batom_t atom)
2091{
2092        BDBG_MSG_TRACE(("batom_pipe_push: >%#lx %#lx", (unsigned long)pipe, (unsigned long)atom));
2093        BDBG_OBJECT_ASSERT(pipe, batom_pipe_t);
2094        BDBG_ASSERT(atom);
2095        BDBG_ASSERT(BLST_SQ_NEXT(atom, pipe_link)==NULL);
2096        BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
2097        BLST_SQ_INSERT_TAIL(&pipe->atoms, atom, pipe_link);
2098        pipe->push_cnt++;
2099        BDBG_MSG_TRACE(("batom_pipe_push: <%#lx:%u %#lx", (unsigned long)pipe, pipe->push_cnt-pipe->pop_cnt, (unsigned long)atom));
2100        return;
2101}
2102
2103batom_t
2104batom_pipe_peek(batom_pipe_t pipe)
2105{
2106        BDBG_OBJECT_ASSERT(pipe, batom_pipe_t);
2107        BDBG_MSG_TRACE(("batom_pipe_peek: >%#lx:%u %#lx", (unsigned long)pipe, pipe->push_cnt-pipe->pop_cnt, BLST_SQ_FIRST(&pipe->atoms)));
2108        return BLST_SQ_FIRST(&pipe->atoms);
2109}
2110
2111void
2112batom_pipe_drop(batom_pipe_t pipe)
2113{
2114        batom_t atom;
2115        atom = BLST_SQ_FIRST(&pipe->atoms);
2116        if(atom) {
2117                BLST_SQ_REMOVE_HEAD(&pipe->atoms, pipe_link);
2118                BLST_SQ_NEXT(atom, pipe_link) = NULL;
2119                BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
2120                pipe->pop_cnt++;
2121        } else {
2122                BDBG_ASSERT(0);
2123        }
2124        BDBG_MSG_TRACE(("batom_pipe_drop: <%#lx:%u", (unsigned long)pipe, pipe->push_cnt-pipe->pop_cnt));
2125        return;
2126}
2127
2128batom_t
2129batom_pipe_pop(batom_pipe_t pipe)
2130{
2131        batom_t atom;
2132        BDBG_MSG_TRACE(("batom_pipe_pop: >%#lx", (unsigned long)pipe));
2133        BDBG_OBJECT_ASSERT(pipe, batom_pipe_t);
2134        atom = BLST_SQ_FIRST(&pipe->atoms);
2135        if(atom) {
2136                BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
2137                BLST_SQ_REMOVE_HEAD(&pipe->atoms, pipe_link);
2138                BLST_SQ_NEXT(atom, pipe_link) = NULL;
2139                pipe->pop_cnt++;
2140        }
2141        BDBG_MSG_TRACE(("batom_pipe_pop: <%#lx:%u %#lx", (unsigned long)pipe, pipe->push_cnt-pipe->pop_cnt, (unsigned long)atom));
2142        return atom;
2143}
2144
2145void
2146batom_pipe_flush(batom_pipe_t pipe)
2147{
2148        batom_t atom;
2149
2150        BDBG_OBJECT_ASSERT(pipe, batom_pipe_t);
2151        while( NULL!=(atom=BLST_SQ_FIRST(&pipe->atoms))) {
2152                BLST_SQ_REMOVE_HEAD(&pipe->atoms, pipe_link);
2153                BLST_SQ_NEXT(atom, pipe_link) = NULL;
2154                BDBG_OBJECT_ASSERT(atom->factory, batom_factory_t);
2155                pipe->pop_cnt++;
2156                batom_release(atom);
2157        }
2158        if(pipe->pop_cnt!=pipe->push_cnt) {
2159                BDBG_WRN(("batom_pipe_flush: runaway atoms: %#lx %u:%u", (unsigned long)pipe, pipe->push_cnt, pipe->pop_cnt));
2160        }
2161        return;
2162}
2163
2164#define B_ATOM_DUMP_MAX 256
2165static void 
2166b_atom_cursor_dump(batom_cursor *c, const char *func, const char *name)
2167{
2168#if BDBG_DEBUG_BUILD
2169        uint8_t line[16];
2170        char split[16];
2171        unsigned i,j;
2172        unsigned off;
2173        unsigned addr;
2174        char str[80];
2175
2176        BDBG_WRN(("%s: %s len: %u bytes vecs:%u left:%d pos:%d(%#x:%u)", func, name, batom_cursor_size(c), c->count, c->left, c->pos-1, c->cursor, c->pos>0?((uint8_t *)c->cursor - (uint8_t *)c->vec[c->pos-1].base):0));
2177        for(i=0;i<c->count;i++) {
2178                BDBG_WRN(("%s: %s vec:%u:%#lx:%u", func, name,  i, (unsigned long)c->vec[i].base, (unsigned)c->vec[i].len));
2179        }
2180        for(addr=0;!BATOM_IS_EOF(c) && addr<B_ATOM_DUMP_MAX;addr+=sizeof(line)) {
2181                for(i=0;i<sizeof(line);i++) {
2182                        uint16_t last_pos = c->pos;
2183                        int b = batom_cursor_next(c);
2184
2185                        if(b==BATOM_EOF) {
2186                                break;
2187                        }
2188                        line[i]=b;
2189                        split[i]= (last_pos==c->pos)?' ':'|';
2190                }
2191                for(off=0,j=0;off<sizeof(str)&&j<i;j++) {
2192                        off+=BKNI_Snprintf(str+off,sizeof(str)-off, "%c%02x", split[j], line[j]);
2193                        if(j==7 && off<sizeof(str)) {
2194                                off+=BKNI_Snprintf(str+off,sizeof(str)-off, " .");
2195                        }
2196                }
2197                BDBG_WRN(("%s: %s 0x%04x:%s", func, name, addr, str));
2198        }
2199#else /* BDBG_DEBUG_BUILD */
2200        BSTD_UNUSED(c);
2201        BSTD_UNUSED(name);
2202        BSTD_UNUSED(func);
2203#endif
2204        return;
2205}
2206
2207void 
2208batom_accum_dump(batom_accum_t acc, const char *name)
2209{
2210        batom_cursor c;
2211
2212        batom_cursor_from_accum(&c, acc);
2213        b_atom_cursor_dump(&c, "batom_accum_t", name);
2214        return;
2215}
2216
2217void 
2218batom_dump(batom_t atom, const char *name)
2219{
2220        batom_cursor c;
2221        BDBG_ASSERT(atom);
2222
2223#if BDBG_DEBUG_BUILD
2224        BDBG_WRN(("batom_dump: %s:%#lx %s ref_cnt:%u len:%u vecs:%u", name, (unsigned long)atom, atom->atom_type==B_ATOM_TYPE_CLONE?"clone":"", atom->ref_cnt, batom_len(atom), batom_get_nvecs(atom)));
2225#endif
2226
2227        batom_cursor_from_atom(&c, atom);
2228        b_atom_cursor_dump(&c, "batom_t", name);
2229        return;
2230}
2231
2232void 
2233batom_cursor_dump(const batom_cursor *src, const char *name)
2234{
2235        batom_cursor c;
2236
2237        BATOM_CLONE(&c, src);
2238        b_atom_cursor_dump(&c, "batom_cursor", name);
2239        return;
2240}
2241
2242void 
2243batom_vec_init(batom_vec *vec, const void *base, size_t len)
2244{
2245        B_ATOM_VEC_INIT(vec, base, len);
2246}
Note: See TracBrowser for help on using the repository browser.