source: trunk/kernel/kern/cluster.c @ 1

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

First import

File size: 16.1 KB
Line 
1/*
2 * cluster.c - Cluster-Manager related operations
3 *
4 * Author  Ghassan Almaless (2008,2009,2010,2011,2012)
5 *         Mohamed Lamine Karaoui (2015)
6 *         Alain Greiner (2016)
7 *
8 * Copyright (c) UPMC Sorbonne Universites
9 *
10 * This file is part of ALMOS-MKH..
11 *
12 * ALMOS-MKH. is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; version 2.0 of the License.
15 *
16 * ALMOS-MKH. is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#include <almos_config.h>
27#include <hal_types.h>
28#include <hal_atomic.h>
29#include <hal_special.h>
30#include <printk.h>
31#include <errno.h>
32#include <spinlock.h>
33#include <core.h>
34#include <scheduler.h>
35#include <list.h>
36#include <cluster.h>
37#include <sysfs.h>
38#include <boot_info.h>
39#include <bits.h>
40#include <ppm.h>
41#include <thread.h>
42#include <kmem.h>
43#include <process.h>
44#include <dqdt.h>
45
46///////////////////////////////////////////////////////////////////////////////////////////
47// Extern global variables
48///////////////////////////////////////////////////////////////////////////////////////////
49
50process_t process_zero;
51
52
53
54//////////////////////////////////
55void cluster_sysfs_register(void)
56{
57        // TODO
58}
59
60/////////////////////////////////////////////////
61error_t cluster_init( struct boot_info_s * info )
62{
63    lpid_t      lpid;     // local process_index
64    lid_t       lid;      // local core index
65
66        cluster_t * cluster = LOCAL_CLUSTER;
67
68    // initialize cluster global parameters
69        cluster->paddr_width     = info->paddr_width; 
70        cluster->x_width         = info->x_width;
71        cluster->y_width         = info->y_width;
72        cluster->x_size          = info->x_size;
73        cluster->y_size          = info->y_size;
74        cluster->io_cxy          = info->io_cxy;
75
76    // initialize cluster local parameters
77        cluster->cores_nr        = info->cores_nr;
78    cluster->cores_in_kernel = info->cores_nr;   // all cpus start in kernel mode
79
80    // initialize kcm lock
81        spinlock_init( &cluster->kcm_lock );
82
83    // initialize txt0 lock
84        remote_spinlock_init( XPTR( local_cxy , &cluster->txt0_lock ) );
85
86    // initialises DQDT
87    cluster->dqdt_root_level = dqdt_init( info->x_size, 
88                                          info->y_size, 
89                                          info->y_width );
90    cluster->threads_var = 0;
91    cluster->pages_var   = 0;
92
93    // initialises embedded PPM
94        ppm_init( &cluster->ppm,
95              info->pages_nr,
96              info->pages_offset );
97
98    // initialises embedded KHM
99        khm_init( &cluster->khm );
100 
101    // initialises embedded KCM
102        kcm_init( &cluster->kcm , KMEM_KCM ); 
103
104    // initialises cores
105        for( lid = 0 ; lid < cluster->cores_nr; lid++ )
106        {
107                core_init( &cluster->core_tbl[lid],    // target core descriptor
108                       lid,                        // local core index
109                       info->core[lid].gid );      // gid from boot_info_t
110        }
111       
112    // initialises RPC fifo
113        rpc_fifo_init( &cluster->rpc_fifo );
114
115    // initialise pref_tbl[] in process manager
116        spinlock_init( &cluster->pmgr.pref_lock );
117    cluster->pmgr.pref_nr = 0;
118    cluster->pmgr.pref_tbl[0] = XPTR( local_cxy , &process_zero );   
119    for( lpid = 1 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ )
120    {
121        cluster->pmgr.pref_tbl[lpid] = XPTR_NULL;
122    }
123
124    // initialise local_list in process manager
125        spinlock_init( &cluster->pmgr.local_lock );
126    list_root_init( &cluster->pmgr.local_root );
127    cluster->pmgr.local_nr = 0;
128
129    // initialise copies_lists in process manager
130    for( lpid = 1 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ )
131    {
132            remote_spinlock_init( XPTR( local_cxy , &cluster->pmgr.copies_lock[lpid] ) );
133        cluster->pmgr.copies_nr[lpid] = 0;
134        xlist_root_init( XPTR( local_cxy , &cluster->pmgr.copies_root[lpid] ) );
135    }   
136
137    hal_wbflush();
138
139    // wait all clusters initialised on barrier located in cluster_io
140    remote_barrier( XPTR( cluster->io_cxy , &cluster->barrier ) ,
141                    cluster->x_size * cluster->y_size );
142
143        return 0;
144} // end cluster_init()
145
146////////////////////////////////////////
147bool_t cluster_is_undefined( cxy_t cxy )
148{
149    cluster_t * cluster = LOCAL_CLUSTER;
150
151    uint32_t y_width = cluster->y_width;
152
153    uint32_t x = cxy >> y_width;
154    uint32_t y = cxy & ((1<<y_width)-1);
155
156    if( x >= cluster->x_size ) return true; 
157    if( y >= cluster->y_size ) return true; 
158
159    return false;
160}
161
162////////////////////////////////////////////////////////////////////////////////////
163//  Cores related functions
164////////////////////////////////////////////////////////////////////////////////////
165
166////////////////////////////////
167void cluster_core_kernel_enter()
168{
169    cluster_t * cluster = LOCAL_CLUSTER;
170        hal_atomic_inc( &cluster->cores_in_kernel );
171}
172
173///////////////////////////////
174void cluster_core_kernel_exit()
175{
176    cluster_t * cluster = LOCAL_CLUSTER;
177        hal_atomic_dec( &cluster->cores_in_kernel );
178}
179
180/////////////////////////////////
181lid_t cluster_select_local_core()
182{
183    uint32_t min = 100;
184    lid_t    sel = 0;
185    lid_t    lid;
186
187    cluster_t * cluster = LOCAL_CLUSTER;
188
189    for( lid = 0 ; lid < cluster->cores_nr ; lid++ )
190    {
191        if( cluster->core_tbl[lid].usage < min )
192        {
193            min = cluster->core_tbl[lid].usage;
194            sel = lid;
195        }
196    } 
197    return sel;
198}
199
200////////////////////////////////////////////////////////////////////////////////////
201//  Process management related functions
202////////////////////////////////////////////////////////////////////////////////////
203
204//////////////////////////////////////////////////////////
205xptr_t cluster_get_reference_process_from_pid( pid_t pid )
206{ 
207    xptr_t xp;   // extended pointer on process descriptor
208
209    cluster_t * cluster = LOCAL_CLUSTER;
210
211    // get owner cluster and lpid
212    cxy_t  owner_cxy = CXY_FROM_PID( pid );
213    lpid_t lpid      = LPID_FROM_PID( pid );
214
215    // Check valid PID
216    if( lpid >= CONFIG_MAX_PROCESS_PER_CLUSTER )
217    {
218        printk("\n[PANIC] in %s : illegal PID\n", __FUNCTION__ );
219        hal_core_sleep();
220    }
221
222    if( local_cxy == owner_cxy )   // local cluster is owner cluster
223    { 
224        xp = cluster->pmgr.pref_tbl[lpid];
225    }
226    else                              // use a remote_lwd to access owner cluster
227    {
228        xp = (xptr_t)hal_remote_lwd( XPTR( owner_cxy , &cluster->pmgr.pref_tbl[lpid] ) );
229    }
230
231    return xp;
232}
233
234////////////////////////////////////////////////
235error_t cluster_pid_alloc( xptr_t    process_xp,
236                           pid_t   * pid )
237{
238    error_t     error;
239    lpid_t      lpid;
240    bool_t      found;
241
242    pmgr_t    * pm         = &LOCAL_CLUSTER->pmgr;
243
244    // get the process manager lock
245    spinlock_lock( &pm->pref_lock );
246
247    // search an empty slot
248    found = false;
249    for( lpid = 0 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ )
250    {
251        if( pm->pref_tbl[lpid] == XPTR_NULL )
252        {
253            found = true;
254            break;
255        }
256    }
257
258    if( found )
259    {
260        // register process in pref_tbl[]
261        pm->pref_tbl[lpid] = process_xp;
262        pm->pref_nr++;
263
264        // returns pid
265        *pid = PID( local_cxy , lpid );
266
267        error = 0;
268    }
269    else
270    {
271        error = EAGAIN;
272    }   
273
274    // release the processs_manager lock
275    spinlock_unlock( &pm->pref_lock );
276
277    return error;
278
279} // end cluster_pid_alloc()
280
281/////////////////////////////////////
282void cluster_pid_release( pid_t pid )
283{
284    cxy_t  owner_cxy  = CXY_FROM_PID( pid );
285    lpid_t lpid       = LPID_FROM_PID( pid );
286
287    // check pid argument
288    if( (lpid >= CONFIG_MAX_PROCESS_PER_CLUSTER) || (owner_cxy != local_cxy) )
289    {
290        printk("\n[PANIC] in %s : illegal PID\n", __FUNCTION__ );
291        hal_core_sleep();
292    }
293
294    pmgr_t  * pm = &LOCAL_CLUSTER->pmgr;
295
296    // get the process manager lock
297    spinlock_lock( &pm->pref_lock );
298
299    // remove process from pref_tbl[]
300    pm->pref_tbl[lpid] = XPTR_NULL;
301    pm->pref_nr--;
302
303    // release the processs_manager lock
304    spinlock_unlock( &pm->pref_lock );
305
306} // end cluster_pid_release()
307
308///////////////////////////////////////////////////////////
309process_t * cluster_get_local_process_from_pid( pid_t pid )
310{
311    process_t    * ret     = NULL;
312    list_entry_t * root    = &LOCAL_CLUSTER->pmgr.local_root;
313    list_entry_t * iter;
314    process_t    * process;
315   
316    LIST_FOREACH( root , iter )
317    {
318        process = LIST_ELEMENT( iter , process_t , local_list );
319        if( process->pid == pid )
320        {
321            ret = process;
322            break;
323        }
324    }
325    return ret;
326
327}  // end cluster_get_local_process_from_pid()
328
329//////////////////////////////////////////////////////
330void cluster_process_local_link( process_t * process )
331{
332    pmgr_t * pm = &LOCAL_CLUSTER->pmgr;
333
334    // get lock protecting the process manager local list
335    spinlock_lock( &pm->local_lock );
336
337    list_add_first( &pm->local_root , &process->local_list );
338    pm->local_nr++;
339
340    // release lock protecting the process manager local list
341    spinlock_unlock( &pm->local_lock );
342}
343
344////////////////////////////////////////////////////////
345void cluster_process_local_unlink( process_t * process )
346{
347    pmgr_t * pm = &LOCAL_CLUSTER->pmgr;
348
349    // get lock protecting the process manager local list
350    spinlock_lock( &pm->local_lock );
351
352    list_unlink( &process->local_list );
353    pm->local_nr--;
354
355    // release lock protecting the process manager local list
356    spinlock_unlock( &pm->local_lock );
357}
358
359///////////////////////////////////////////////////////
360void cluster_process_copies_link( process_t * process )
361{
362    pmgr_t * pm = &LOCAL_CLUSTER->pmgr;
363
364    // get owner cluster identifier CXY and process LPID
365    pid_t    pid        = process->pid;
366    cxy_t    owner_cxy  = CXY_FROM_PID( pid );
367    lpid_t   lpid       = LPID_FROM_PID( pid );
368
369    // get extended pointer on lock protecting copies_list[lpid]
370    xptr_t copies_lock  = hal_remote_lwd( XPTR( owner_cxy , &pm->copies_lock[lpid] ) );
371
372    // get extended pointer on the copies_list[lpid] root
373    xptr_t copies_root  = hal_remote_lwd( XPTR( owner_cxy , &pm->copies_root[lpid] ) );
374
375    // get extended pointer on the local copies_list entry
376    xptr_t copies_entry = XPTR( local_cxy , &process->copies_list );
377
378    // get lock protecting copies_list[lpid]
379    remote_spinlock_lock( copies_lock );
380
381    xlist_add_first( copies_root , copies_entry );
382    hal_remote_atomic_add( XPTR( owner_cxy , &pm->copies_nr[lpid] ) , 1 );
383
384    // release lock protecting copies_list[lpid]
385    remote_spinlock_unlock( copies_lock );
386}
387
388/////////////////////////////////////////////////////////
389void cluster_process_copies_unlink( process_t * process )
390{
391    pmgr_t * pm = &LOCAL_CLUSTER->pmgr;
392
393    // get owner cluster identifier CXY and process LPID
394    pid_t    pid        = process->pid;
395    cxy_t    owner_cxy  = CXY_FROM_PID( pid );
396    lpid_t   lpid       = LPID_FROM_PID( pid );
397
398    // get extended pointer on lock protecting copies_list[lpid]
399    xptr_t copies_lock  = hal_remote_lwd( XPTR( owner_cxy , &pm->copies_lock[lpid] ) );
400
401    // get extended pointer on the local copies_list entry
402    xptr_t copies_entry = XPTR( local_cxy , &process->copies_list );
403
404    // get lock protecting copies_list[lpid]
405    remote_spinlock_lock( copies_lock );
406
407    xlist_unlink( copies_entry );
408    hal_remote_atomic_add( XPTR( owner_cxy , &pm->copies_nr[lpid] ) , -1 );
409
410    // release lock protecting copies_list[lpid]
411    remote_spinlock_unlock( copies_lock );
412}
413
414////////////////////////////////////////////////////////////////////////////////////////
415// TODO Il me semble que la seule chose que fait ce kernel thread à chaque réveil
416// est de mettre à jour la DQDT, et de se rendormir... A-t-on besoin d'un thread ? [AG]
417//////////////////////////////////////////////////////////////////////////////////////////
418
419#if 0
420void * cluster_manager_thread( void * arg )
421{
422        register struct dqdt_cluster_s * root;
423        register struct cluster_s      * root_home;
424
425        register uint32_t                tm_start;
426        register uint32_t                tm_end;
427        register uint32_t                cpu_id;
428        struct cluster_s               * cluster;
429        struct thread_s                * this;
430        struct event_s                   event;
431        struct alarm_info_s              info;
432        register uint32_t                cntr;
433        register bool_t                  isRootMgr;
434        register uint32_t                period;
435
436        cpu_enable_all_irq( NULL );
437
438        cluster   = arg;
439        this      = CURRENT_THREAD;
440        cpu_id    = cpu_get_id();
441        root      = dqdt_root;
442        root_home = dqdt_root->home;
443        isRootMgr = (cluster == root_home) ? true : false;
444        cntr      = 0;
445        period    = (isRootMgr) ?
446                CONFIG_DQDT_ROOTMGR_PERIOD * MSEC_PER_TICK :
447                CONFIG_DQDT_MGR_PERIOD * MSEC_PER_TICK;
448
449        event_set_senderId(&event, this);
450        event_set_priority(&event, E_CHR);
451        event_set_handler(&event, &manager_alarm_event_handler);
452 
453        info.event = &event;
454        thread_preempt_disable(CURRENT_THREAD);
455
456    // infinite loop
457        while(1)
458        {
459                tm_start = cpu_time_stamp();
460                dqdt_update();
461                tm_end   = cpu_time_stamp();
462
463                if(isRootMgr)
464                {
465                        if((cntr % 10) == 0)
466                        {
467                                printk(INFO, "INFO: cpu %d, DQDT update ended [ %u - %u ]\n",
468                                       cpu_id,
469                                       tm_end,
470                                       tm_end - tm_start);
471
472                                dqdt_print_summary(root);
473                        }
474                }
475
476                alarm_wait( &info , period );
477                sched_sleep(this);
478                cntr ++;
479        }
480
481        return NULL;
482} // end cluster_manager_thread()
483
484//////////////////////////////////////////
485EVENT_HANDLER(manager_alarm_event_handler)
486{
487        struct thread_s *manager;
488 
489        manager = event_get_senderId(event);
490 
491        thread_preempt_disable(CURRENT_THREAD);
492
493        //printk(INFO, "%s: cpu %d [%u]\n", __FUNCTION__, cpu_get_id(), cpu_time_stamp());
494
495        sched_wakeup(manager);
496 
497        thread_preempt_enable(CURRENT_THREAD);
498
499        return 0;
500}
501
502///////////////////////////////////////////////
503EVENT_HANDLER(cluster_key_create_event_handler)
504{
505        struct cluster_s *cluster;
506        struct thread_s *sender;
507        ckey_t *ckey;
508        uint32_t key;
509
510        sender  = event_get_senderId(event);
511        ckey    = event_get_argument(event);
512        cluster = current_cluster;
513        key     = cluster->next_key;
514
515        while((key < CLUSTER_TOTAL_KEYS_NR) && (cluster->keys_tbl[key] != NULL))
516                key ++;
517
518        if(key < CLUSTER_TOTAL_KEYS_NR)
519        {
520                ckey->val = key;
521                cluster->keys_tbl[key] = (void *) 0x1; // Reserved
522                cluster->next_key = key;
523                event_set_error(event, 0);
524        }
525        else
526                event_set_error(event, ENOSPC);
527
528        sched_wakeup(sender);
529        return 0;
530}
531
532///////////////////////////////////////////////
533EVENT_HANDLER(cluster_key_delete_event_handler)
534{
535        struct cluster_s *cluster;
536        struct thread_s *sender;
537        ckey_t *ckey;
538        uint32_t key;
539
540        sender  = event_get_senderId(event);
541        ckey    = event_get_argument(event);
542        cluster = current_cluster;
543        key     = ckey->val;
544
545        if(key < cluster->next_key)
546                cluster->next_key = key;
547
548        cluster->keys_tbl[key] = NULL;
549        event_set_error(event, 0);
550
551        sched_wakeup(sender);
552        return 0;
553}
554
555#define _CKEY_CREATE  0x0
556#define _CKEY_DELETE  0x1
557
558error_t cluster_do_key_op(ckey_t *key, uint32_t op)
559{
560        struct event_s event;
561        struct thread_s *this;
562        struct cluster_s *cluster;
563        struct cpu_s *cpu;
564
565        this = CURRENT_THREAD;
566
567        event_set_priority(&event, E_FUNC);
568        event_set_senderId(&event, this);
569        event_set_argument(&event, key);
570
571        if(op == _CKEY_CREATE)
572                event_set_handler(&event, cluster_key_create_event_handler);
573        else
574                event_set_handler(&event, cluster_key_delete_event_handler);
575
576        cluster = current_cluster;
577        cpu     = cluster->bscluster->bscpu;
578        event_send(&event, &cpu->re_listner);
579
580        sched_sleep(this);
581
582        return event_get_error(&event);
583}
584
585error_t cluster_key_create(ckey_t *key)
586{
587        return cluster_do_key_op(key, _CKEY_CREATE);
588}
589
590error_t cluster_key_delete(ckey_t *key)
591{
592        return cluster_do_key_op(key, _CKEY_DELETE);
593}
594
595void* cluster_getspecific(ckey_t *key)
596{
597        struct cluster_s *cluster;
598
599        cluster = current_cluster;
600        return cluster->keys_tbl[key->val];
601}
602
603void  cluster_setspecific(ckey_t *key, void *val)
604{
605        struct cluster_s *cluster;
606
607        cluster = current_cluster;
608        cluster->keys_tbl[key->val] = val;
609}
610#endif
Note: See TracBrowser for help on using the repository browser.