source: trunk/libs/libalmosmkh/almosmkh.c @ 637

Last change on this file since 637 was 637, checked in by alain, 4 years ago

Introduce the non-standard pthread_parallel_create() system call
and re-write the <fft> and <sort> applications to improve the
intrinsic paralelism in applications.

File size: 49.0 KB
Line 
1/*
2 * almosmkh.c - User level ALMOS-MKH specific library implementation.
3 *
4 * Author     Alain Greiner (2016,2017,2018,2019)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <almosmkh.h>
25#include <hal_user.h>
26#include <hal_macros.h>
27#include <hal_shared_types.h>
28#include <syscalls_numbers.h>
29#include <string.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <mman.h>
34
35#define  DEBUG_REMOTE_MALLOC     0
36#define  DEBUG_PTHREAD_PARALLEL  1
37 
38//////////////////////////////////////////////////////////////////////////////////////
39/////////////     Non standard system calls    ///////////////////////////////////////
40//////////////////////////////////////////////////////////////////////////////////////
41
42//////////////////////////
43int fg( unsigned int pid )
44{
45    return hal_user_syscall( SYS_FG,
46                             (reg_t)pid, 0, 0, 0 );
47}
48
49//////////////////////////////
50int is_fg( unsigned int   pid,
51           unsigned int * owner )
52{
53    return hal_user_syscall( SYS_IS_FG,
54                             (reg_t)pid,
55                             (reg_t)owner, 0, 0 );
56}
57
58//////////////////////////////////////
59int get_config( unsigned int * x_size,
60                unsigned int * y_size,
61                unsigned int * ncores )
62{
63    return hal_user_syscall( SYS_GET_CONFIG,
64                             (reg_t)x_size,
65                             (reg_t)y_size,
66                             (reg_t)ncores, 0 );
67}
68
69////////////////////////////////////
70int get_core_id( unsigned int * cxy,
71                 unsigned int * lid )
72{
73    return hal_user_syscall( SYS_GET_CORE_ID,
74                             (reg_t)cxy,
75                             (reg_t)lid, 0, 0 );
76}
77
78/////////////////////////////////////
79int get_nb_cores( unsigned int   cxy,
80                  unsigned int * ncores )
81{
82    return hal_user_syscall( SYS_GET_NB_CORES,
83                             (reg_t)cxy,
84                             (reg_t)ncores, 0, 0 );
85}
86
87///////////////////////////////////////////
88int get_best_core( unsigned int   base_cxy,
89                   unsigned int   level,
90                   unsigned int * cxy,
91                   unsigned int * lid )
92{
93    return hal_user_syscall( SYS_GET_BEST_CORE,
94                             (reg_t)base_cxy,
95                             (reg_t)level,
96                             (reg_t)cxy,
97                             (reg_t)lid );
98}
99
100///////////////////////////////////////////
101int get_cycle( unsigned long long * cycle )
102{
103    return hal_user_syscall( SYS_GET_CYCLE,
104                             (reg_t)cycle, 0, 0, 0 );
105}
106
107//////////////////////////////////
108int place_fork( unsigned int cxy )
109{
110    return hal_user_syscall( SYS_PLACE_FORK,
111                             (reg_t)cxy, 0, 0, 0 );
112}
113
114/////////////////////////////////
115int utls( unsigned int operation,
116          unsigned int value )
117{
118    return hal_user_syscall( SYS_UTLS,
119                             (reg_t)operation,
120                             (reg_t)value, 0, 0 );
121}
122
123///////////////////////////////
124unsigned int get_uint32( void )
125{
126    unsigned int  i;
127    int           c;    // ASCII character value
128
129    unsigned char buf[32];
130
131    unsigned int  save          = 0;
132    unsigned int  value         = 0;
133    unsigned int  done          = 0;
134    unsigned int  overflow      = 0;
135    unsigned int  length        = 0;
136
137    // get characters
138    while (done == 0) 
139    {
140        // read one character
141        c = getchar();
142
143        // analyse this character
144        if ( ((c > 0x2F) && (c < 0x3A)) ||                      // 0 to 9
145             ((c > 0x40) && (c < 0x47)) ||                      // A to F
146             ((c > 0x60) && (c < 0x67)) ||                      // a to f
147             (((c == 0x58) || (c == 0x78)) && (length == 1)) )  // X or x
148        {
149            putchar( c );                       // echo
150            if ( c > 0x60 )  c = c - 0x20;      // to upper case
151            buf[length] = (unsigned char)c;
152            length++;                     
153        }
154        else if (c == 0x0A)                                     // LF character
155        {
156            done = 1;
157        }
158        else if ( (c == 0x7F) ||                                // DEL character
159                  (c == 0x08) )                                 // BS  character
160        {
161            if ( length > 0 ) 
162            {
163                length--;         
164                printf("\b \b");                // BS /  / BS
165            }
166        }
167        else if ( c == 0 )                                      // EOF character
168        {
169            return -1;
170        }
171
172        // test buffer overflow
173        if ( length >= 32 ) 
174        {
175            overflow = 1;
176            done     = 1;
177        }
178    }  // end while characters
179
180    // string to int conversion with overflow detection
181    if ( overflow == 0 )
182    {
183        // test (decimal / hexa)
184        if( (buf[0] == 0x30) && (buf[1] == 0x58) )     // hexadecimal input
185        {
186            for (i = 2; (i < length) && (overflow == 0) ; i++)
187            {
188                if( buf[i] < 0x40 ) value = (value << 4) + (buf[i] - 0x30);
189                else                value = (value << 4) + (buf[i] - 0x37);
190                if (value < save) overflow = 1; 
191                save = value;
192            }
193        }
194        else                                           // decimal input
195        {
196            for (i = 0; (i < length) && (overflow == 0) ; i++) 
197            {
198                value = (value * 10) + (buf[i] - 0x30);
199                if (value < save) overflow = 1; 
200                save = value;
201            }
202        }
203    } 
204
205    // final evaluation
206    if ( overflow == 0 )
207    {
208        // return value
209        return value;
210    }
211    else
212    {
213        // cancel all echo characters
214        for (i = 0; i < length ; i++) 
215        {
216            printf("\b \b");                  // BS /  / BS
217        }
218
219        // echo character '0'
220        putchar( '0' );
221
222        // return 0 value
223        return 0;
224    }
225}  // end get_uint32()
226
227//////////////////////////////
228int get_string( char * string,
229                int    maxlen )
230{
231    int c;
232    int done   = 0;
233    int length = 0;
234
235    while( done == 0 )
236    {
237        // check buffer overflow
238        if( length >= maxlen-1 )
239        {
240            return -1;                      // return failure   
241        }
242
243        // read one character
244        c = getchar();
245
246        // analyse this character
247        if ( (c >= 0x20) && (c < 0x7F) )    // printable character
248        {
249            putchar( c );                   // echo
250            string[length] = (char)c;       // register character in string
251            length++;                       // update length
252        }
253        else if (c == 0x0A)                 // LF character marks end of string
254        {
255            done = 1;
256        }
257        else if ( (c == 0x7F) ||            // DEL character
258                  (c == 0x08) )             // BS  character
259        {
260            if ( length > 0 ) 
261            {
262                length--;         
263                printf("\b \b");            // BS /  / BS
264            }
265        }
266        else if ( c == 0 )                  // EOF character
267        {
268            return -1;                      // return failure
269        }
270    }
271
272    // set NUL character in string and return success
273    string[length] = 0;
274    return 0;
275
276}  // end get_string()
277
278//////////////////////////////////////////////////////////////////////////////////////
279///////////////    non standard debug functions    ///////////////////////////////////
280//////////////////////////////////////////////////////////////////////////////////////
281
282////////////////////////////////////
283void display_string( char * string )
284{
285    hal_user_syscall( SYS_DISPLAY,
286                      DISPLAY_STRING,
287                      (reg_t)string, 0, 0 );
288}
289
290/////////////////////////////////////////////////////
291int display_vmm( unsigned int cxy, unsigned int pid )
292{
293    return hal_user_syscall( SYS_DISPLAY,
294                             DISPLAY_VMM,
295                             (reg_t)cxy,
296                             (reg_t)pid, 0 );
297} 
298
299////////////////////////////////////
300int display_sched( unsigned int cxy,
301                   unsigned int lid )
302{
303    return hal_user_syscall( SYS_DISPLAY,
304                             DISPLAY_SCHED,
305                             (reg_t)cxy,
306                             (reg_t)lid, 0 );
307} 
308
309////////////////////////////////////////////////
310int display_cluster_processes( unsigned int cxy,
311                               unsigned int owned )
312{
313    return hal_user_syscall( SYS_DISPLAY,
314                             DISPLAY_CLUSTER_PROCESSES,
315                             (reg_t)cxy,
316                             (reg_t)owned, 0 );
317} 
318
319////////////////////////////////////////
320int display_busylocks( unsigned int pid,
321                       unsigned int trdid )
322{
323    return hal_user_syscall( SYS_DISPLAY,
324                             DISPLAY_BUSYLOCKS,
325                             (reg_t)pid,
326                             (reg_t)trdid, 0 );
327} 
328
329/////////////////////////
330int display_chdev( void )
331{
332    return hal_user_syscall( SYS_DISPLAY,
333                             DISPLAY_CHDEV, 0, 0, 0 );
334} 
335
336///////////////////////
337int display_vfs( void )
338{
339    return hal_user_syscall( SYS_DISPLAY,
340                             DISPLAY_VFS, 0, 0, 0 );
341} 
342
343////////////////////////////////////////////////
344int display_txt_processes( unsigned int txt_id )
345{
346    return hal_user_syscall( SYS_DISPLAY,
347                             DISPLAY_TXT_PROCESSES,
348                             (reg_t)txt_id, 0, 0 );
349} 
350
351////////////////////////
352int display_dqdt( void )
353{
354    return hal_user_syscall( SYS_DISPLAY,
355                             DISPLAY_DQDT, 0, 0, 0 );
356} 
357
358///////////////////////////////////////
359int display_mapper( char        * path,
360                    unsigned int  page_id,
361                    unsigned int  nbytes)
362{
363    return hal_user_syscall( SYS_DISPLAY,
364                             DISPLAY_MAPPER,
365                             (reg_t)path,
366                             (reg_t)page_id,
367                             (reg_t)nbytes );
368} 
369
370///////////////////////////////////////
371int display_barrier( unsigned int pid )
372{
373    return hal_user_syscall( SYS_DISPLAY,
374                             DISPLAY_BARRIER,
375                             (reg_t)pid, 0, 0 );
376} 
377
378///////////////////////////////////////
379int display_fat( unsigned int  page_id,
380                 unsigned int  nb_entries )
381{
382    return hal_user_syscall( SYS_DISPLAY,
383                             DISPLAY_FAT,
384                             (reg_t)page_id,
385                             (reg_t)nb_entries, 0 );
386} 
387
388///////////////////////////////
389int trace( unsigned int active,
390           unsigned int cxy, 
391           unsigned int lid )
392{
393    return hal_user_syscall( SYS_TRACE,
394                             (reg_t)active,
395                             (reg_t)cxy,
396                             (reg_t)lid, 0 );
397}
398
399/////////////////
400void idbg( void )
401{
402   char          cmd;
403
404   while( 1 )
405   {
406        // display prompt
407        printf("\n[idbg] cmd = ");
408
409        // get a one character command
410        cmd = (char)getchar();
411
412        // display all busylocks owned by thread(pid,trdid)
413        if( cmd == 'b' )
414        {
415            printf("b / pid = ");
416            unsigned int pid = get_uint32();
417            printf(" / trdid = ");
418            unsigned int trdid = get_uint32();
419            display_busylocks( pid , trdid );
420        }
421        // return to calling process
422        else if( cmd == 'c' )
423        {
424            printf("c\n");
425            break;
426        }
427        // display FAT mapper(page,entries)
428        else if( cmd == 'f' )
429        {
430            printf("f / page = ");
431            unsigned int page = get_uint32();
432            printf(" / entries = ");
433            unsigned int entries = get_uint32();
434            display_fat( page , entries );
435        }
436        // list all supported commands
437        else if( cmd == 'h' )
438        {
439            printf("h\n" 
440                   "- b : display on TXT0 busylocks taken by thread[pid,trdid]\n"
441                   "- c : resume calling process execution\n"
442                   "- f : display on TXT0 FAT mapper[page,entries]\n"
443                   "- h : list of supported commands\n"
444                   "- m : display on TXT0 mapper[path,page,nbytes]\n"
445                   "- p : display on TXT0 process descriptors in cluster[cxy]\n"
446                   "- q : display on TXT0 DQDT state\n"
447                   "- s : display on TXT0 scheduler state for core[cxy,lid]\n"
448                   "- t : display on TXT0 process decriptors attached to TXT[tid]\n"
449                   "- v : display on TXT0 VMM state for process[cxy,pid]\n"
450                   "- x : force calling process to exit\n"
451                   "- y : activate/desactivate trace for core[cxy,lid]\n"
452                   );
453        }
454        // display MAPPER(path,page,nbytes)
455        else if( cmd == 'm' )
456        {
457            char  path[128];
458            printf("m / path = ");
459            int error = get_string( path , 128 );
460            printf(" / page = ");
461            unsigned int page = get_uint32();
462            printf(" / nbytes = ");
463            unsigned int nbytes = get_uint32();
464            if( error == 0 ) display_mapper( path , page , nbytes );
465        }
466        // display all processes in cluster(cxy)
467        else if( cmd == 'p' )
468        {
469            printf("p / cxy = ");
470            unsigned int cxy = get_uint32();
471            display_cluster_processes( cxy , 0 );
472        }
473        // display DQDT
474        else if( cmd == 'q' )
475        {
476            printf("q\n");
477            display_dqdt();
478        }
479        // display scheduler state for core(cxy,lid)
480        else if( cmd == 's' )
481        {
482            printf("s / cxy = ");
483            unsigned int cxy = get_uint32();
484            printf(" / lid = ");
485            unsigned int lid = get_uint32();
486            display_sched( cxy , lid );
487        }
488        // display all processes attached to TXT(txt_id)
489        else if( cmd == 't' )
490        {
491            printf("t / txt_id = ");
492            unsigned int txt_id = get_uint32();
493            display_txt_processes( txt_id );
494        }
495        // display vmm state for process(cxy, pid)
496        else if( cmd == 'v' )
497        {
498            printf("v / cxy = ");
499            unsigned int cxy = get_uint32();
500            printf(" / pid = ");
501            unsigned int pid = get_uint32();
502            display_vmm( cxy , pid );
503        }
504        // force the calling process to exit
505        else if( cmd == 'x' )
506        {
507            printf("x\n");
508            exit( 0 );
509        }
510        // activate scheduler trace for core(cxy,lid)
511        else if( cmd == 'y' )
512        {
513            printf("y / active = ");
514            unsigned int active = get_uint32();
515            printf(" / cxy = ");
516            unsigned int cxy    = get_uint32();
517            printf(" / lid = ");
518            unsigned int lid    = get_uint32();
519            trace( active , cxy , lid );
520        }
521    }  // en while
522}  // end idbg()
523
524
525/////////////////////////////////////////////////////////////////////////////////////////
526///////////////    non standard remote_malloc    ////////////////////////////////////////
527/////////////////////////////////////////////////////////////////////////////////////////
528
529/////////////////////////////////////////////////////////////////////////////////////////
530// Global variable defining the allocator array (one per cluster)
531// This array (about 16 Kbytes ) will be stored in the data segment
532// of any application linked with this libray.
533/////////////////////////////////////////////////////////////////////////////////////////
534
535malloc_store_t   store[MALLOC_MAX_CLUSTERS];
536
537// Macro returning the smallest power of 2 larger or equal to size value
538
539#define GET_SIZE_INDEX(size)                (size <= 0x00000001) ? 0  :\
540                                            (size <= 0x00000002) ? 1  :\
541                                            (size <= 0x00000004) ? 2  :\
542                                            (size <= 0x00000008) ? 3  :\
543                                            (size <= 0x00000010) ? 4  :\
544                                            (size <= 0x00000020) ? 5  :\
545                                            (size <= 0x00000040) ? 6  :\
546                                            (size <= 0x00000080) ? 7  :\
547                                            (size <= 0x00000100) ? 8  :\
548                                            (size <= 0x00000200) ? 9  :\
549                                            (size <= 0x00000400) ? 10 :\
550                                            (size <= 0x00000800) ? 11 :\
551                                            (size <= 0x00001000) ? 12 :\
552                                            (size <= 0x00002000) ? 13 :\
553                                            (size <= 0x00004000) ? 14 :\
554                                            (size <= 0x00008000) ? 15 :\
555                                            (size <= 0x00010000) ? 16 :\
556                                            (size <= 0x00020000) ? 17 :\
557                                            (size <= 0x00040000) ? 18 :\
558                                            (size <= 0x00080000) ? 19 :\
559                                            (size <= 0x00100000) ? 20 :\
560                                            (size <= 0x00200000) ? 21 :\
561                                            (size <= 0x00400000) ? 22 :\
562                                            (size <= 0x00800000) ? 23 :\
563                                            (size <= 0x01000000) ? 24 :\
564                                            (size <= 0x02000000) ? 25 :\
565                                            (size <= 0x04000000) ? 26 :\
566                                            (size <= 0x08000000) ? 27 :\
567                                            (size <= 0x10000000) ? 28 :\
568                                            (size <= 0x20000000) ? 29 :\
569                                            (size <= 0x40000000) ? 30 :\
570                                            (size <= 0x80000000) ? 31 :\
571                                                                   32
572
573////////////////////////////////////////////////////////////////////////////////////////////
574// This static function display the current state of the allocator in cluster <cxy>.
575////////////////////////////////////////////////////////////////////////////////////////////
576
577#if DEBUG_REMOTE_MALLOC
578static void display_free_array( unsigned int cxy )
579{
580    unsigned int next;
581    unsigned int id;
582    unsigned int iter;
583
584    printf("\n*****   store[%x] base = %x / size = %x\n", 
585    cxy , store[cxy].store_base, store[cxy].store_size );
586    for ( id = 0 ; id < 32 ; id++ )
587    { 
588        next = store[cxy].free[id];
589        printf(" - free[%d] = " , id );
590        iter = 0;
591        while ( next != 0 )
592        {
593            printf("%x | ", next );
594            next = (*(unsigned int*)next);
595            iter++;
596        }
597        printf("0\n");
598    }
599}  // end display_free_array()
600#endif
601
602
603////////////////////////////////////////////////////////////////////i//////////////////////
604// This static function initialises the store in the cluster identified by the <cxy>
605// arguments. It is called by the malloc() or remote_malloc when a specific store(x,y)
606// is accessed for the first time by a remote() or remote_malloc() request.
607// It uses the mmap( MAP_REMOTE ) syscall to allocate a new vseg mapped in cluster (cxy).
608////////////////////////////////////////////////////////////////////i//////////////////////
609// @ cxy        : target cluster identifier (fixed format).
610// @ store_size : store size (bytes).
611// # return without setting the initialized field in store(cxy) if failure.
612////////////////////////////////////////////////////////////////////i//////////////////////
613static void store_init( unsigned int cxy,
614                        unsigned int store_size )
615{
616    unsigned int   store_base;       // store base address
617    unsigned int   free_index;       // index in free[array]
618
619    unsigned int   alloc_base;       // alloc[] array base
620    unsigned int   alloc_size;       // alloc[] array size
621    unsigned int   alloc_index;      // index in alloc[array]
622
623    unsigned int   iter;             // iterator
624
625#if DEBUG_REMOTE_MALLOC
626unsigned int core_cxy;
627unsigned int core_lid;
628get_core_id( &core_cxy , &core_lid );
629printf("\n[%s] core[%x,%d] enter for store[%x] / size = %x\n",
630__FUNCTION__, core_cxy, core_lid, cxy, store_size );
631#endif
632
633    // get index in free[] array from size
634    free_index = GET_SIZE_INDEX( store_size );
635
636    // check store size power of 2
637    if( store_size != (unsigned int)(1<<free_index) )
638    {
639        printf("\n[ERROR] in %s : store[%x] size not power of 2 / size = %x\n",
640        __FUNCTION__, cxy , store_size );
641        return;
642    }
643
644    // allocate store in virtual space
645    void * vadr = mmap( NULL,                     // MAP_FIXED not supported
646                        store_size,
647                        PROT_READ | PROT_WRITE,
648                        MAP_REMOTE| MAP_SHARED,
649                        cxy,                      // fd is cluster identifier
650                        0 );                      // offset unused
651
652    if( vadr == NULL )
653    {
654        printf("\n[ERROR] in %s : cannot mmap store[%x]\n",
655        __FUNCTION__, cxy );
656        return;
657    }
658
659    store_base = (unsigned int)vadr;
660
661    // check allocated store alignment
662    if( store_base % store_size )
663    {
664        printf("\n[ERROR] in %s : store[%x] not aligned / base = %x / size = %x\n",
665        __FUNCTION__, cxy , store_base , store_size );
666        return;
667    }
668
669#if DEBUG_REMOTE_MALLOC
670printf("\n[%s] core[%x,%d] created vseg %x for store[%x]\n",
671__FUNCTION__, core_cxy, core_lid, store_base, cxy );
672#endif
673
674    // compute size of block containing alloc[] array
675    alloc_size = store_size / MALLOC_MIN_BLOCK_SIZE;
676    if ( alloc_size < MALLOC_MIN_BLOCK_SIZE) alloc_size = MALLOC_MIN_BLOCK_SIZE;
677
678    // get index for the corresponding block
679    alloc_index = GET_SIZE_INDEX( alloc_size );
680
681    // compute alloc[] array base address
682    alloc_base = store_base + store_size - alloc_size;
683
684    // reset the free[] array
685    for ( iter = 0 ; iter < 32 ; iter++ )
686    {
687        store[cxy].free[iter] = 0;
688    }
689
690    // split the store into various sizes blocks,
691    // initializes the free[] array and NEXT pointers
692    // base is the block base address
693    unsigned int   base = store_base;
694    unsigned int * ptr;
695    for ( iter = free_index-1 ; iter >= alloc_index ; iter-- )
696    {
697        store[cxy].free[iter] = base;
698        ptr = (unsigned int*)base;
699        *ptr = 0;
700        base = base + (1<<iter);
701    }
702
703    // initialize store mutex
704    if( pthread_mutex_init( &store[cxy].mutex , NULL ) )
705    {
706        printf("\n[ERROR] in %s : cannot initialize mutex for store[%x]\n", 
707        __FUNCTION__, cxy );
708        return;
709    }
710
711    store[cxy].cxy         = cxy;
712    store[cxy].store_base  = store_base;
713    store[cxy].store_size  = store_size;
714    store[cxy].alloc_size  = alloc_size;
715    store[cxy].alloc_base  = alloc_base;
716    store[cxy].initialized = MALLOC_INITIALIZED;
717
718
719#if DEBUG_REMOTE_MALLOC
720printf("\n[%s] core[%x,%d] completed store[%x] initialisation\n",
721__FUNCTION__, core_cxy, core_lid, cxy );
722#endif
723
724#if (DEBUG_REMOTE_MALLOC & 1)
725display_free_array( cxy );
726#endif
727
728}  // end store_init()
729
730////////////////////////////////////////////////////////
731static unsigned int split_block( malloc_store_t * store,
732                                 unsigned int     vaddr, 
733                                 unsigned int     searched_index,
734                                 unsigned int     requested_index )
735{
736    // push the upper half block into free[searched_index-1]
737    unsigned int* new            = (unsigned int*)(vaddr + (1<<(searched_index-1)));
738    *new                         = store->free[searched_index-1]; 
739    store->free[searched_index-1] = (unsigned int)new;
740       
741    if ( searched_index == requested_index + 1 )  // terminal case: return lower half block
742    {
743        return vaddr;
744    }
745    else            // non terminal case : lower half block must be split again
746    {                               
747        return split_block( store, vaddr, searched_index-1, requested_index );
748    }
749} // end split_block()
750
751//////////////////////////////////////////////////////
752static unsigned int get_block( malloc_store_t * store,
753                               unsigned int     searched_index,
754                               unsigned int     requested_index )
755{
756    // test terminal case
757    if ( (unsigned int)(1<<searched_index) > store->store_size )  // failure
758    {
759        return 0;
760    }
761    else                            // search a block in free[searched_index]
762    {
763        unsigned int vaddr = store->free[searched_index];
764        if ( vaddr == 0 )     // block not found : search in free[searched_index+1]
765        {
766            return get_block( store, searched_index+1, requested_index );
767        }
768        else                // block found : pop it from free[searched_index]
769        {
770            // pop the block from free[searched_index]
771            unsigned int next = *((unsigned int*)vaddr); 
772            store->free[searched_index] = next;
773           
774            // test if the block must be split
775            if ( searched_index == requested_index )  // no split required
776            {
777                return vaddr;
778            }
779            else                                      // split is required
780            {
781                return split_block( store, vaddr, searched_index, requested_index );
782            }
783        } 
784    }
785} // end get_block()
786
787////////////////////////////////////////
788void * remote_malloc( unsigned int size,
789                      unsigned int cxy )
790{
791    int error;
792
793#if DEBUG_REMOTE_MALLOC
794unsigned int core_cxy;
795unsigned int core_lid;
796get_core_id( &core_cxy , &core_lid );
797printf("\n[%s] core[%x,%d] enter for size = %x / target_cxy = %x\n",
798__FUNCTION__ , core_cxy, core_lid, size , cxy );
799#endif
800
801    // check arguments
802    if( size == 0 )
803    {
804        printf("\n[ERROR] in %s : requested size = 0 \n",
805        __FUNCTION__ );
806        return NULL;
807    }
808    if( cxy >= MALLOC_MAX_CLUSTERS )
809    {
810        printf("\n[ERROR] in %s : illegal cluster %x\n",
811        __FUNCTION__ , cxy );
812        return NULL;
813    }
814
815    // initializes target store if required
816    if( store[cxy].initialized != MALLOC_INITIALIZED )
817    {
818        store_init( cxy , MALLOC_LOCAL_STORE_SIZE );
819
820        if( store[cxy].initialized != MALLOC_INITIALIZED )
821        {
822            printf("\n[ERROR] in %s : cannot allocate store in cluster %x\n",
823            __FUNCTION__ , cxy );
824            return NULL;
825        }
826    }
827
828    // normalize size
829    if ( size < MALLOC_MIN_BLOCK_SIZE ) size = MALLOC_MIN_BLOCK_SIZE;
830
831    // compute requested_index for the free[] array
832    unsigned int requested_index = GET_SIZE_INDEX( size );
833
834    // take the lock protecting access to store[cxy]
835    error = pthread_mutex_lock( &store[cxy].mutex );
836
837    if( error )
838    {
839        printf("\n[ERROR] in %s : cannot take the lock protecting store in cluster %x\n",
840        __FUNCTION__ , cxy );
841        return NULL;
842    }
843
844    // call the recursive function get_block
845    unsigned int base = get_block( &store[cxy], 
846                                   requested_index, 
847                                   requested_index );
848
849    // check block found
850    if (base == 0)
851    {
852        pthread_mutex_unlock( &store[cxy].mutex );
853        printf("\n[ERROR] in %s : no more space in cluster %x\n",
854        __FUNCTION__ , cxy );
855        return NULL;
856    }
857
858    // compute pointer in alloc[] array
859    unsigned        offset = (base - store[cxy].store_base) / MALLOC_MIN_BLOCK_SIZE;
860    unsigned char * ptr    = (unsigned char*)(store[cxy].alloc_base + offset);
861
862    // update alloc_array
863    *ptr = requested_index;
864
865    // release the lock
866    pthread_mutex_unlock( &store[cxy].mutex );
867 
868#if DEBUG_REMOTE_MALLOC
869printf("\n[%s] core[%x,%d] exit / base = %x / size = %x / from store[%x]\n",
870__FUNCTION__, core_cxy, core_lid, base , size , cxy );
871#endif
872
873    return (void*) base;
874
875} // end remote_malloc()
876
877//////////////////////////////////////////
878void * remote_calloc ( unsigned int count,
879                       unsigned int size,
880                       unsigned int cxy )
881{
882    void * ptr = remote_malloc( count * size , cxy );
883    memset( ptr , 0 , count * size );
884    return ptr;
885}
886
887//////////////////////////////////
888void * remote_realloc( void * ptr,
889                       unsigned int size,
890                       unsigned int cxy )
891{
892    // simple allocation when (ptr == NULL)
893    if( ptr == NULL )
894    {
895        return remote_malloc( size , cxy );
896    }
897
898    // simple free when (size == 0)
899    if( size == 0 )
900    {
901        remote_free( ptr , cxy );
902        return NULL;
903    }
904
905    // check cxy and ptr in general case
906    if( cxy >= MALLOC_MAX_CLUSTERS )
907    {
908        printf("\n[ERROR] in %s : illegal cluster index %x\n",
909        __FUNCTION__ , cxy );
910        return NULL;
911    }
912
913    unsigned int base = (unsigned int)ptr;
914
915    if( (base < store[cxy].store_base) || 
916        (base >= (store[cxy].store_base + store[cxy].store_size)) )
917    {
918        printf("\n[ERROR] in %s : illegal pointer = %x\n",
919        __FUNCTION__, ptr );
920        return NULL;
921    }
922 
923    // compute index in free[] array
924    int index = (base - store[cxy].store_base) / MALLOC_MIN_BLOCK_SIZE;
925
926    // compute old size
927    char        * pchar    = (char *) (store[cxy].alloc_base + index);
928    unsigned int  old_size = (unsigned int)(1 << ((int) *pchar));
929
930    // allocate a new block
931    void * new_ptr = remote_malloc( size , cxy );
932
933    // save old data to new block
934    int min_size = (int)((size < old_size) ? size : old_size);
935    memcpy( new_ptr, ptr, min_size );
936
937    // release old block
938    remote_free( ptr , cxy );
939
940    return new_ptr;
941
942}  // end remote_realloc()
943
944
945//////////////////////////////////////////////////////
946static void update_free_array( malloc_store_t * store,
947                               unsigned int     base,
948                               unsigned int     size_index )
949{
950    // This recursive function try to merge the released block
951    // with the companion block if this companion block is free.
952    // This companion has the same size, and almost the same address
953    // (only one address bit is different)
954    // - If the companion is not in free[size_index],
955    //   the released block is pushed in free[size_index].
956    // - If the companion is found, it is evicted from free[size_index]
957    //   and the merged bloc is pushed in the free[size_index+1].
958
959
960    // compute released block size
961    unsigned int size = 1<<size_index;
962
963    // compute companion block and merged block base addresses
964    unsigned int companion_base; 
965    unsigned int merged_base; 
966
967    if ( (base & size) == 0 )   // the released block is aligned on (2*size)
968    {
969        companion_base  = base + size;
970        merged_base     = base;
971    }
972    else
973    {
974        companion_base  = base - size;
975        merged_base     = base - size;
976    }
977
978    // scan all blocks in free[size_index]
979    // the iter & prev variables are actually addresses
980    unsigned int  found = 0;
981    unsigned int  iter  = store->free[size_index];
982    unsigned int  prev  = (unsigned int)&store->free[size_index];
983    while ( iter ) 
984    {
985        if ( iter == companion_base ) 
986        {
987            found = 1;
988            break;
989        }
990        prev = iter;
991        iter = *(unsigned int*)iter;
992    }
993
994    if ( found == 0 )  // Companion not found => push in free[size_index] 
995    {
996        *(unsigned int*)base   = store->free[size_index];
997        store->free[size_index] = base;
998    }
999    else               // Companion found : merge
1000    {
1001        // evict the searched block from free[size_index]
1002        *(unsigned int*)prev = *(unsigned int*)iter;
1003
1004        // call the update_free() function for free[size_index+1]
1005        update_free_array( store, merged_base , size_index+1 );
1006    }
1007}  // end update_free_array()
1008
1009////////////////////////////////////
1010void remote_free( void        * ptr,
1011                  unsigned int  cxy )
1012{
1013
1014#if DEBUG_REMOTE_MALLOC
1015printf("\n[MALLOC] %s : enter for block = %x / cxy = %x\n",
1016__FUNCTION__, ptr, cxy );
1017#endif
1018
1019    unsigned int base = (unsigned int)ptr;
1020
1021    // check cxy value
1022    if( cxy >= MALLOC_MAX_CLUSTERS )
1023    {
1024        printf("\n[ERROR] in %s : illegal cluster index %x\n",
1025        __FUNCTION__ , cxy );
1026        return;
1027    }
1028
1029    // check ptr value
1030    if( (base < store[cxy].store_base) || 
1031        (base >= (store[cxy].store_base + store[cxy].store_size)) )
1032    {
1033        printf("\n[ERROR] in %s : illegal pointer for released block = %x\n",
1034        __FUNCTION__, ptr );
1035        return;
1036    }
1037 
1038    // get the lock protecting store[cxy]
1039    pthread_mutex_lock( &store[cxy].mutex );
1040
1041    // compute released block index in alloc[] array
1042    unsigned index = (base - store[cxy].store_base ) / MALLOC_MIN_BLOCK_SIZE;
1043 
1044    // get the released block size_index
1045    unsigned char* pchar      = (unsigned char*)(store[cxy].alloc_base + index);
1046    unsigned int   size_index = (unsigned int)*pchar;
1047
1048    // check block is allocated
1049    if ( size_index == 0 )
1050    {
1051        pthread_mutex_unlock( &store[cxy].mutex );
1052        printf("\n[ERROR] in %s : released block not allocated / ptr = %x\n",
1053        __FUNCTION__, ptr );
1054        return;
1055    }
1056
1057    // check released block alignment
1058    if ( base % (1 << size_index) )
1059    {
1060        pthread_mutex_unlock( &store[cxy].mutex );
1061        printf("\n[ERROR] in %s : released block not aligned / ptr = %x\n",
1062        __FUNCTION__, ptr );
1063        return;
1064    }
1065
1066    // reset the alloc[index] entry
1067    *pchar = 0;
1068
1069    // call the recursive function update_free_array()
1070    update_free_array( &store[cxy], base, size_index ); 
1071
1072    // release the lock
1073    pthread_mutex_unlock( &store[cxy].mutex );
1074
1075#if DEBUG_REMOTE_MALLOC
1076printf("\n[MALLOC] %s : conmpletes for block = %x / cxy = %x\n",
1077__FUNCTION__, ptr, cxy );
1078#endif
1079
1080} // end remote_free()
1081
1082/////////////////////////////////////////////////////////////////////////////////////////
1083///////////////    non standard pthread_parallel_create    //////////////////////////////
1084/////////////////////////////////////////////////////////////////////////////////////////
1085
1086#define X_MAX                   16              // max number of clusters in a row
1087#define Y_MAX                   16              // max number of clusters in a column
1088#define CLUSTERS_MAX            X_MAX * Y_MAX
1089#define LEVEL_MAX               5
1090#define CORES_MAX               4               // max number of cores per cluster
1091
1092typedef struct build_args_s           
1093{
1094    unsigned char       cxy;                    // this thread cluster identifier
1095    unsigned char       level;                  // this thread level in quad-tree
1096    unsigned char       parent_cxy;             // parent thread cluster identifier
1097    unsigned char       root_level;             // quad-tree root level
1098    void              * work_func;              // pointer on work function pointer
1099    void              * work_args_array;        // pointer on 2D array of pointers
1100    pthread_barrier_t * parent_barriers_array;  // pointer on 1D array of barriers
1101    unsigned int        error;                  // return value : 0 if success
1102}
1103build_args_t;
1104
1105/////////////////////////////////////////////////////////////////////////////////////////
1106//      Global variables used for inter-thread communications
1107/////////////////////////////////////////////////////////////////////////////////////////
1108
1109pthread_attr_t    build_attr   [CLUSTERS_MAX][LEVEL_MAX];   // POSIX thread attributes
1110
1111build_args_t      build_args   [CLUSTERS_MAX][LEVEL_MAX];   // build function arguments
1112
1113pthread_barrier_t build_barrier[CLUSTERS_MAX][LEVEL_MAX];   // parent/child synchro
1114
1115pthread_attr_t    work_attr    [CLUSTERS_MAX][CORES_MAX];    // POSIX thread attributes
1116
1117//////////////////////////////////////////////////////////
1118static void pthread_recursive_build( build_args_t * args )
1119{
1120    unsigned int   trdid;         // unused (required by pthread_create()
1121
1122    // get arguments
1123    unsigned int        cxy                   = args->cxy;
1124    unsigned int        level                 = args->level;
1125    unsigned int        parent_cxy            = args->parent_cxy;
1126    unsigned int        root_level            = args->root_level;
1127    void              * work_func             = args->work_func;
1128    void              * work_args_array       = args->work_args_array;
1129    pthread_barrier_t * parent_barriers_array = args->parent_barriers_array;
1130
1131    // set error default value
1132    build_args[cxy][level].error = 0;
1133
1134    ///////////////////////////////////////////////////////////
1135    if( level == 0 )             // children are "work" threads
1136    {
1137        unsigned int   lid;           // core local index
1138        unsigned int   ncores;        // number of cores in a cluster
1139
1140        // get number of cores per cluster
1141        get_nb_cores( cxy , &ncores );
1142
1143        // kill process if no active core in cluster
1144        // TODO this "if" should be replaced by an "assert" [AG]
1145        if( ncores == 0 )
1146        {
1147            printf("\n[PANIC] in %s : no active core in cluster %x\n",
1148            __FUNCTION__ , cxy );
1149
1150            // report error to parent
1151            build_args[parent_cxy][level+1].error = 1;
1152
1153            // kill process
1154            exit( EXIT_FAILURE );
1155        }
1156
1157        // initialize the parent_barrier
1158        if( pthread_barrier_init( &parent_barriers_array[cxy] , NULL , ncores + 1 ) )
1159        {
1160            printf("\n[ERROR] in %s : cannot initialise barrier for build thread[%x][%d]\n",
1161            __FUNCTION__ , cxy , level );
1162
1163            // report error to parent
1164            build_args[parent_cxy][level+1].error = 1;
1165        }
1166
1167#if DEBUG_PTHREAD_PARALLEL
1168printf("\n[%s] <build> thread[%x][%d] created barrier / %d children\n",
1169__FUNCTION__, cxy, level, ncores + 1 );
1170#endif
1171        // create (ncores) "work" threads
1172        for ( lid = 0 ; lid < ncores ; lid++ )
1173        {
1174            // set attributes for thread[cxy][lid]
1175            work_attr[cxy][lid].attributes = PT_ATTR_DETACH |
1176                                             PT_ATTR_CLUSTER_DEFINED |
1177                                             PT_ATTR_CORE_DEFINED;
1178            work_attr[cxy][lid].cxy        = cxy;
1179            work_attr[cxy][lid].lid        = lid;
1180
1181            // compute pointer on thread[cxy][lid] arguments
1182            void * work_args = *((void **)work_args_array + (cxy * CORES_MAX) + lid);
1183
1184            // create thread
1185            if ( pthread_create( &trdid,                  // unused
1186                                 &work_attr[cxy][lid],
1187                                 work_func,
1188                                 work_args ) ) 
1189            {
1190                printf("\n[ERROR] in %s : cannot create work thread[%x,%x]\n",
1191                __FUNCTION__ , cxy , lid );
1192
1193                // report error to parent
1194                build_args[parent_cxy][level+1].error = 1;
1195            }
1196
1197#if DEBUG_PTHREAD_PARALLEL
1198printf("\n[%s] <build> thread[%x][%d] created <work> thread[%x][%d]\n",
1199__FUNCTION__, cxy, level, cxy, lid );
1200#endif
1201        }
1202
1203        // wait on barrier until "work" children threads completed
1204        if( pthread_barrier_wait( &parent_barriers_array[cxy] ) )
1205        {
1206            printf("\n[ERROR] in %s / first barrier for <build> thread[%x][%d]\n",
1207            __FUNCTION__ , cxy , level );
1208
1209            // report error to parent
1210            build_args[parent_cxy][level+1].error = 1;
1211        }
1212
1213#if DEBUG_PTHREAD_PARALLEL
1214printf("\n[%s] <build> thread[%x][%d] resume after children completion\n",
1215__FUNCTION__, cxy, level );
1216#endif
1217
1218    }  // end level == 0
1219
1220    ////////////////////////////////////////////////////////////
1221    else                        // children are "build" threads
1222    {
1223        // the 4 children threads can be created in any core of each quarters
1224        // of the parent macro-cluster
1225
1226        unsigned int parent_x;          // X coordinate of parent macro-cluster
1227        unsigned int parent_y;          // Y coordinate of parent macro-cluster
1228        unsigned int child_x;           // X coordinate of child macro-cluster
1229        unsigned int child_y;           // Y coordinate of child macro-cluster
1230        unsigned int child_cxy[2][2];   // selected cluster for child thread
1231        unsigned int child_lid[2][2];   // selected core index for child thread
1232        int          child_sts[2][2];   // -1 if error / 0 if success / +1 if not found
1233        unsigned int x;                 // X loop index for children
1234        unsigned int y;                 // Y loop index for children
1235       
1236        unsigned int nb_children = 0;
1237
1238        // get parent macro-cluster mask and half-size from level
1239        unsigned int mask = (1 << level) - 1;
1240        unsigned int half = (level > 0) ? (1 << (level - 1)) : 0;
1241
1242        // get parent macro-cluster coordinates
1243        parent_x = HAL_X_FROM_CXY( cxy ) & ~mask;
1244        parent_y = HAL_Y_FROM_CXY( cxy ) & ~mask;
1245
1246        // get child_cxy and child_lid for up to 4 children threads : 00 / 01 / 10 / 11
1247        for (x = 0 ; x < 2 ; x++)
1248        {
1249            // compute child macro-cluster X coordinate
1250            child_x = (x == 0) ? parent_x : (parent_x + half);
1251
1252            for (y = 0 ; y < 2 ; y++)
1253            {
1254                // compute child macro-cluster Y coordinate
1255                child_y = (y == 0) ? parent_y : (parent_y + half);
1256
1257                // select the best core in macro-cluster
1258                child_sts[x][y] = get_best_core( HAL_CXY_FROM_XY( child_x , child_y ),
1259                                                 level-1,
1260                                                 &child_cxy[x][y],
1261                                                 &child_lid[x][y] );
1262
1263                if( child_sts[x][y] < 0 )  // failure => report error
1264                {
1265                    printf("\n[ERROR] in %s : illegal arguments for <build> thread[%x,%x]\n",
1266                    __FUNCTION__ , cxy , level );
1267
1268                    // report error to parent
1269                    build_args[parent_cxy][level+1].error = 1;
1270                }
1271                else if (child_sts[x][y] > 0 )  // macro-cluster undefined => does nothing
1272                {
1273                }
1274                else                            // core found
1275                {
1276                    nb_children++;
1277                }
1278            }  // end for y
1279        }  // end for x
1280
1281        // kill process if no active core in cluster
1282        // TODO this "if" should be replaced by an "assert" [AG]
1283        if( nb_children == 0 )
1284        {
1285            printf("\n[PANIC] in %s : no active core in macro cluster [%x,%d]\n",
1286            __FUNCTION__ , cxy , level );
1287
1288            // report error to parent
1289            build_args[parent_cxy][level+1].error = 1;
1290
1291            // kill process
1292            exit( EXIT_FAILURE );
1293        }
1294
1295        // initialize the barrier for (nb_children + 1)
1296        if( pthread_barrier_init( &build_barrier[cxy][level], NULL , nb_children + 1 ) )
1297        {
1298            printf("\n[error] in %s : cannot initialise barrier for build thread[%x][%d]\n",
1299            __FUNCTION__ , cxy , level );
1300
1301            // report error to parent
1302            build_args[parent_cxy][level+1].error = 1;
1303        }
1304
1305#if DEBUG_PTHREAD_PARALLEL
1306printf("\n[%s] <build> thread[%x][%d] created barrier / %d children\n",
1307__FUNCTION__, cxy, level, nb_children + 1 );
1308#endif
1309        // create 1 to 4 children threads
1310        for (x = 0 ; x < 2 ; x++)
1311        {
1312            for (y = 0 ; y < 2 ; y++)
1313            {
1314                // thread is created only if macro-cluster is active
1315                if( child_sts[x][y] == 0 )
1316                {
1317                    unsigned int tgt_cxy = child_cxy[x][y];
1318                    unsigned int tgt_lid = child_lid[x][y];
1319
1320                    // set child thread attributes
1321                    build_attr[tgt_cxy][level-1].attributes = PT_ATTR_DETACH |
1322                                                              PT_ATTR_CLUSTER_DEFINED |
1323                                                              PT_ATTR_CORE_DEFINED;
1324                    build_attr[tgt_cxy][level-1].cxy        = tgt_cxy;
1325                    build_attr[tgt_cxy][level-1].lid        = tgt_lid;
1326
1327                    // propagate build function arguments
1328                    build_args[tgt_cxy][level-1].cxy                   = child_cxy[x][y];
1329                    build_args[tgt_cxy][level-1].level                 = level-1;
1330                    build_args[tgt_cxy][level-1].parent_cxy            = cxy;
1331                    build_args[tgt_cxy][level-1].root_level            = root_level;
1332                    build_args[tgt_cxy][level-1].work_func             = work_func;
1333                    build_args[tgt_cxy][level-1].work_args_array       = work_args_array;
1334                    build_args[tgt_cxy][level-1].parent_barriers_array = parent_barriers_array;
1335                   
1336                    // create thread
1337                    if( pthread_create( &trdid,                         
1338                                        &build_attr[tgt_cxy][level-1],   
1339                                        &pthread_recursive_build,                         
1340                                        &build_args[tgt_cxy][level-1] ) )
1341                    {
1342                        printf("\n[ERROR] in %s : cannot create build thread[%x][%d]\n",
1343                        __FUNCTION__ , child_cxy , level -1 );
1344
1345                        // report error to parent
1346                        build_args[parent_cxy][level+1].error = 1;
1347                    }
1348
1349#if DEBUG_PTHREAD_PARALLEL
1350printf("\n[%s] <build> thread[%x][%d] created <build> thread[%x][%d] on core[%x,%d]\n",
1351__FUNCTION__, cxy, level, tgt_cxy, level - 1, tgt_cxy, tgt_lid );
1352#endif
1353                }  //end if sts[x][y]
1354            }  // end for y
1355        }  // end for x
1356       
1357        // wait on barrier until "build" children threads completed
1358        if( pthread_barrier_wait( &build_barrier[cxy][level] ) )
1359        {
1360            printf("\n[ERROR] in %s / first barrier for <build> thread[%x][%d]\n",
1361            __FUNCTION__ , cxy , level );
1362
1363            // report error to parent
1364            build_args[parent_cxy][level+1].error = 1;
1365        }
1366
1367#if DEBUG_PTHREAD_PARALLEL
1368printf("\n[%s] <build> thread[%x][%d] resume after children completion\n",
1369__FUNCTION__, cxy, level );
1370#endif
1371
1372    }  // end level > 0
1373
1374    // report error to parent when required
1375    if( build_args[cxy][level].error )
1376    {
1377        build_args[parent_cxy][level+1].error = 1;
1378    }
1379
1380    // all <build> threads - but the root -
1381    // signal completion to parent thread and exit
1382    if( level < root_level )
1383    {
1384        if( pthread_barrier_wait( &build_barrier[parent_cxy][level+1] ) )
1385        {
1386            printf("\n[ERROR] in %s / second barrier for <build> thread[%x][%d]\n",
1387            __FUNCTION__ , cxy , level );
1388
1389            // report error to parent
1390            build_args[parent_cxy][level+1].error = 1;
1391        }
1392   
1393#if DEBUG_PTHREAD_PARALLEL
1394printf("\n[%s] <build> thread[%x][%d] exit\n",
1395__FUNCTION__, cxy , level );
1396#endif
1397        // "build" thread exit
1398        pthread_exit( NULL );
1399    }
1400}  // end pthread_recursive_build()
1401
1402///////////////////////////////////////////////////////
1403int pthread_parallel_create( unsigned int   root_level,
1404                             void         * work_func,
1405                             void         * work_args_array,
1406                             void         * parent_barriers_array )
1407{
1408    unsigned int   root_cxy;
1409    unsigned int   root_lid;    // unused, but required by get_core_id()
1410   
1411#if DEBUG_PTHREAD_PARALLEL
1412printf("\n[%s] enter / root_level %d / func %x / args %x / barriers %x\n",
1413__FUNCTION__, root_level, work_func, work_args_array, parent_barriers_array );
1414#endif
1415
1416    // get calling thread cluster
1417    get_core_id( &root_cxy , &root_lid );
1418
1419    // set the build function arguments for the root <build> thread
1420    build_args[root_cxy][root_level].cxy                   = root_cxy; 
1421    build_args[root_cxy][root_level].level                 = root_level;
1422    build_args[root_cxy][root_level].root_level            = root_level;
1423    build_args[root_cxy][root_level].work_func             = work_func;
1424    build_args[root_cxy][root_level].work_args_array       = work_args_array;
1425    build_args[root_cxy][root_level].parent_barriers_array = parent_barriers_array;
1426   
1427    // call the recursive build function
1428    pthread_recursive_build( &build_args[root_cxy][root_level] );
1429
1430    // check error
1431    if( build_args[root_cxy][root_level].error )
1432    {
1433        printf("\n[error] in  %s\n", __FUNCTION__ );
1434        return -1;
1435    }
1436
1437    return 0;
1438
1439}  // end pthread_parallel_create()
1440
1441
1442
1443// Local Variables:
1444// tab-width: 4
1445// c-basic-offset: 4
1446// c-file-offsets:((innamespace . 0)(inline-open . 0))
1447// indent-tabs-mode: nil
1448// End:
1449// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1450
1451
1452
Note: See TracBrowser for help on using the repository browser.