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

Last change on this file since 640 was 640, checked in by alain, 5 years ago

Remove all RPCs in page-fault handling.

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