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

Last change on this file since 650 was 650, checked in by alain, 3 years ago

Simplify the pthread_parallel_create() syscall.

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