Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/kernel.hfa

    r6d1790c r121be3e  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:26 2020
    13 // Update Count     : 22
     12// Last Modified On : Wed Dec  4 07:54:51 2019
     13// Update Count     : 18
    1414//
    1515
    1616#pragma once
     17
     18#include <stdbool.h>
    1719
    1820#include "invoke.h"
     
    2022#include "coroutine.hfa"
    2123
    22 #include "containers/list.hfa"
    23 
    2424extern "C" {
    25         #include <bits/pthreadtypes.h>
    26         #include <linux/types.h>
     25#include <pthread.h>
     26#include <semaphore.h>
    2727}
    2828
     
    3232        __spinlock_t lock;
    3333        int count;
    34         __queue_t($thread) waiting;
     34        __queue_t(thread_desc) waiting;
    3535};
    3636
    3737void  ?{}(semaphore & this, int count = 1);
    3838void ^?{}(semaphore & this);
    39 bool   P (semaphore & this);
    40 bool   V (semaphore & this);
    41 bool   V (semaphore & this, unsigned count);
     39void   P (semaphore & this);
     40void   V (semaphore & this);
    4241
    4342
     
    4645extern struct cluster * mainCluster;
    4746
    48 // Processor id, required for scheduling threads
    49 struct __processor_id_t {
    50         unsigned id:24;
    51         bool full_proc:1;
    52 
    53         #if !defined(__CFA_NO_STATISTICS__)
    54                 struct __stats_t * stats;
    55         #endif
    56 };
    57 
     47enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule, Callback };
     48
     49typedef void (*__finish_callback_fptr_t)(void);
     50
     51//TODO use union, many of these fields are mutually exclusive (i.e. MULTI vs NOMULTI)
     52struct FinishAction {
     53        FinishOpCode action_code;
     54        /*
     55        // Union of possible actions
     56        union {
     57                // Option 1 : locks and threads
     58                struct {
     59                        // 1 thread or N thread
     60                        union {
     61                                thread_desc * thrd;
     62                                struct {
     63                                        thread_desc ** thrds;
     64                                        unsigned short thrd_count;
     65                                };
     66                        };
     67                        // 1 lock or N lock
     68                        union {
     69                                __spinlock_t * lock;
     70                                struct {
     71                                        __spinlock_t ** locks;
     72                                        unsigned short lock_count;
     73                                };
     74                        };
     75                };
     76                // Option 2 : action pointer
     77                __finish_callback_fptr_t callback;
     78        };
     79        /*/
     80        thread_desc * thrd;
     81        thread_desc ** thrds;
     82        unsigned short thrd_count;
     83        __spinlock_t * lock;
     84        __spinlock_t ** locks;
     85        unsigned short lock_count;
     86        __finish_callback_fptr_t callback;
     87        //*/
     88};
     89static inline void ?{}(FinishAction & this) {
     90        this.action_code = No_Action;
     91        this.thrd = 0p;
     92        this.lock = 0p;
     93}
     94static inline void ^?{}(FinishAction &) {}
     95
     96// Processor
    5897coroutine processorCtx_t {
    5998        struct processor * proc;
     
    61100
    62101// Wrapper around kernel threads
    63 struct __attribute__((aligned(128))) processor {
     102struct processor {
    64103        // Main state
    65         inline __processor_id_t;
     104        // Coroutine ctx who does keeps the state of the processor
     105        struct processorCtx_t runner;
    66106
    67107        // Cluster from which to get threads
    68108        struct cluster * cltr;
    69109
    70         // Set to true to notify the processor should terminate
    71         volatile bool do_terminate;
    72 
    73         // Coroutine ctx who does keeps the state of the processor
    74         struct processorCtx_t runner;
    75 
    76110        // Name of the processor
    77111        const char * name;
     
    79113        // Handle to pthreads
    80114        pthread_t kernel_thread;
     115
     116        // RunThread data
     117        // Action to do after a thread is ran
     118        struct FinishAction finish;
    81119
    82120        // Preemption data
     
    87125        bool pending_preemption;
    88126
    89         // Idle lock (kernel semaphore)
    90         __bin_sem_t idle;
    91 
    92         // Termination synchronisation (user semaphore)
     127        // Idle lock
     128        __bin_sem_t idleLock;
     129
     130        // Termination
     131        // Set to true to notify the processor should terminate
     132        volatile bool do_terminate;
     133
     134        // Termination synchronisation
    93135        semaphore terminated;
    94136
     
    97139
    98140        // Link lists fields
    99         DLISTED_MGD_IMPL_IN(processor)
    100 
    101         #if !defined(__CFA_NO_STATISTICS__)
    102                 int print_stats;
    103                 bool print_halts;
    104         #endif
     141        struct __dbg_node_proc {
     142                struct processor * next;
     143                struct processor * prev;
     144        } node;
    105145
    106146#ifdef __CFA_DEBUG__
     
    110150};
    111151
    112 void  ?{}(processor & this, const char name[], struct cluster & cltr);
     152void  ?{}(processor & this, const char * name, struct cluster & cltr);
    113153void ^?{}(processor & this);
    114154
    115155static inline void  ?{}(processor & this)                    { this{ "Anonymous Processor", *mainCluster}; }
    116156static inline void  ?{}(processor & this, struct cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
    117 static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
    118 
    119 DLISTED_MGD_IMPL_OUT(processor)
    120 
    121 //-----------------------------------------------------------------------------
    122 // I/O
    123 struct __io_data;
    124 
    125 // IO poller user-thread
    126 // Not using the "thread" keyword because we want to control
    127 // more carefully when to start/stop it
    128 struct $io_ctx_thread {
    129         struct __io_data * ring;
    130         single_sem sem;
    131         volatile bool done;
    132         $thread self;
    133 };
    134 
    135 
    136 struct io_context {
    137         $io_ctx_thread thrd;
    138 };
    139 
    140 struct io_context_params {
    141         int num_entries;
    142         int num_ready;
    143         int submit_aff;
    144         bool eager_submits:1;
    145         bool poller_submits:1;
    146         bool poll_submit:1;
    147         bool poll_complete:1;
    148 };
    149 
    150 void  ?{}(io_context_params & this);
    151 
    152 void  ?{}(io_context & this, struct cluster & cl);
    153 void  ?{}(io_context & this, struct cluster & cl, const io_context_params & params);
    154 void ^?{}(io_context & this);
    155 
    156 struct io_cancellation {
    157         __u64 target;
    158 };
    159 
    160 static inline void  ?{}(io_cancellation & this) { this.target = -1u; }
    161 static inline void ^?{}(io_cancellation &) {}
    162 bool cancel(io_cancellation & this);
    163 
    164 //-----------------------------------------------------------------------------
    165 // Cluster Tools
    166 
    167 // Intrusives lanes which are used by the relaxed ready queue
    168 struct __attribute__((aligned(128))) __intrusive_lane_t;
    169 void  ?{}(__intrusive_lane_t & this);
    170 void ^?{}(__intrusive_lane_t & this);
    171 
    172 // Counter used for wether or not the lanes are all empty
    173 struct __attribute__((aligned(128))) __snzi_node_t;
    174 struct __snzi_t {
    175         unsigned mask;
    176         int root;
    177         __snzi_node_t * nodes;
    178 };
    179 
    180 void  ?{}( __snzi_t & this, unsigned depth );
    181 void ^?{}( __snzi_t & this );
    182 
    183 //TODO adjust cache size to ARCHITECTURE
    184 // Structure holding the relaxed ready queue
    185 struct __ready_queue_t {
    186         // Data tracking how many/which lanes are used
    187         // Aligned to 128 for cache locality
    188         __snzi_t snzi;
    189 
    190         // Data tracking the actual lanes
    191         // On a seperate cacheline from the used struct since
    192         // used can change on each push/pop but this data
    193         // only changes on shrink/grow
    194         struct {
    195                 // Arary of lanes
    196                 __intrusive_lane_t * volatile data;
    197 
    198                 // Number of lanes (empty or not)
    199                 volatile size_t count;
    200         } lanes;
    201 };
    202 
    203 void  ?{}(__ready_queue_t & this);
    204 void ^?{}(__ready_queue_t & this);
    205 
    206 // Idle Sleep
    207 struct __cluster_idles {
    208         // Spin lock protecting the queue
    209         volatile uint64_t lock;
    210 
    211         // Total number of processors
    212         unsigned total;
    213 
    214         // Total number of idle processors
    215         unsigned idle;
    216 
    217         // List of idle processors
    218         dlist(processor, processor) list;
    219 };
     157static inline void  ?{}(processor & this, const char * name) { this{name, *mainCluster }; }
     158
     159static inline [processor *&, processor *& ] __get( processor & this ) {
     160        return this.node.[next, prev];
     161}
    220162
    221163//-----------------------------------------------------------------------------
    222164// Cluster
    223 struct __attribute__((aligned(128))) cluster {
     165struct cluster {
     166        // Ready queue locks
     167        __spinlock_t ready_queue_lock;
     168
    224169        // Ready queue for threads
    225         __ready_queue_t ready_queue;
     170        __queue_t(thread_desc) ready_queue;
    226171
    227172        // Name of the cluster
     
    231176        Duration preemption_rate;
    232177
    233         // List of idle processors
    234         __cluster_idles idles;
     178        // List of processors
     179        __spinlock_t proc_list_lock;
     180        __dllist_t(struct processor) procs;
     181        __dllist_t(struct processor) idles;
     182        unsigned int nprocessors;
    235183
    236184        // List of threads
    237185        __spinlock_t thread_list_lock;
    238         __dllist_t(struct $thread) threads;
     186        __dllist_t(struct thread_desc) threads;
    239187        unsigned int nthreads;
    240188
     
    244192                cluster * prev;
    245193        } node;
    246 
    247         struct {
    248                 io_context * ctxs;
    249                 unsigned cnt;
    250         } io;
    251 
    252         #if !defined(__CFA_NO_STATISTICS__)
    253                 struct __stats_t * stats;
    254                 int print_stats;
    255         #endif
    256194};
    257195extern Duration default_preemption();
    258196
    259 void ?{} (cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params);
     197void ?{} (cluster & this, const char * name, Duration preemption_rate);
    260198void ^?{}(cluster & this);
    261199
    262 static inline void ?{} (cluster & this)                                            { io_context_params default_params;    this{"Anonymous Cluster", default_preemption(), 1, default_params}; }
    263 static inline void ?{} (cluster & this, Duration preemption_rate)                  { io_context_params default_params;    this{"Anonymous Cluster", preemption_rate, 1, default_params}; }
    264 static inline void ?{} (cluster & this, const char name[])                         { io_context_params default_params;    this{name, default_preemption(), 1, default_params}; }
    265 static inline void ?{} (cluster & this, unsigned num_io)                           { io_context_params default_params;    this{"Anonymous Cluster", default_preemption(), num_io, default_params}; }
    266 static inline void ?{} (cluster & this, Duration preemption_rate, unsigned num_io) { io_context_params default_params;    this{"Anonymous Cluster", preemption_rate, num_io, default_params}; }
    267 static inline void ?{} (cluster & this, const char name[], unsigned num_io)        { io_context_params default_params;    this{name, default_preemption(), num_io, default_params}; }
    268 static inline void ?{} (cluster & this, const io_context_params & io_params)                                            { this{"Anonymous Cluster", default_preemption(), 1, io_params}; }
    269 static inline void ?{} (cluster & this, Duration preemption_rate, const io_context_params & io_params)                  { this{"Anonymous Cluster", preemption_rate, 1, io_params}; }
    270 static inline void ?{} (cluster & this, const char name[], const io_context_params & io_params)                         { this{name, default_preemption(), 1, io_params}; }
    271 static inline void ?{} (cluster & this, unsigned num_io, const io_context_params & io_params)                           { this{"Anonymous Cluster", default_preemption(), num_io, io_params}; }
    272 static inline void ?{} (cluster & this, Duration preemption_rate, unsigned num_io, const io_context_params & io_params) { this{"Anonymous Cluster", preemption_rate, num_io, io_params}; }
    273 static inline void ?{} (cluster & this, const char name[], unsigned num_io, const io_context_params & io_params)        { this{name, default_preemption(), num_io, io_params}; }
    274 
    275 static inline [cluster *&, cluster *& ] __get( cluster & this ) __attribute__((const)) { return this.node.[next, prev]; }
    276 
    277 static inline struct processor * active_processor() { return publicTLS_get( this_processor ); } // UNSAFE
    278 static inline struct cluster   * active_cluster  () { return publicTLS_get( this_processor )->cltr; }
    279 
    280 #if !defined(__CFA_NO_STATISTICS__)
    281         void print_stats_now( cluster & this, int flags );
    282 
    283         static inline void print_stats_at_exit( cluster & this, int flags ) {
    284                 this.print_stats |= flags;
    285         }
    286 
    287         static inline void print_stats_at_exit( processor & this, int flags ) {
    288                 this.print_stats |= flags;
    289         }
    290 
    291         void print_halts( processor & this );
    292 #endif
     200static inline void ?{} (cluster & this)                           { this{"Anonymous Cluster", default_preemption()}; }
     201static inline void ?{} (cluster & this, Duration preemption_rate) { this{"Anonymous Cluster", preemption_rate}; }
     202static inline void ?{} (cluster & this, const char * name)        { this{name, default_preemption()}; }
     203
     204static inline [cluster *&, cluster *& ] __get( cluster & this ) {
     205        return this.node.[next, prev];
     206}
     207
     208static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE
     209static inline struct cluster   * active_cluster  () { return TL_GET( this_processor )->cltr; }
    293210
    294211// Local Variables: //
Note: See TracChangeset for help on using the changeset viewer.