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

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

First import

File size: 7.7 KB
Line 
1/*
2 * kern/event.c - Per-CPU Events-Manager
3 *
4 * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless
5 * Copyright (c) 2011,2012 UPMC Sorbonne Universites
6 *
7 * This file is part of ALMOS-kernel.
8 *
9 * ALMOS-kernel is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2.0 of the License.
12 *
13 * ALMOS-kernel is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <types.h>
24#include <cpu.h>
25#include <cluster.h>
26#include <device.h>
27#include <pmm.h>
28#include <event.h>
29#include <cpu-trace.h>
30#include <thread.h>
31
32/** Initialize event */
33error_t event_init(struct event_s *event)
34{
35        /* nothing to do in this version */
36        return 0;
37}
38
39/** Destroy event */
40void event_destroy(struct event_s *event)
41{
42        /* nothing to do in this version */
43}
44
45/** Destroy event listner */
46void event_listner_destroy(struct event_listner_s *el)
47{
48        /* nothing to do in this version */
49}
50
51error_t event_listner_init(struct event_listner_s *el)
52{
53        error_t err;
54        register uint_t i;
55 
56        el->flags = 0;
57        el->prio = 0;
58        err = 0;
59
60        for(i=0; i < E_PRIO_NR; i++)
61        {
62                list_root_init(&el->tbl[i].root);
63                el->tbl[i].count = 0;
64        }
65
66
67        return 0;
68}
69
70
71static void local_event_send(struct event_s *event, struct event_listner_s *el, bool_t isFIFO) 
72{
73        uint_t prio;
74        uint_t irq_state;
75
76        prio = event_get_priority(event);
77
78        cpu_disable_all_irq(&irq_state);
79
80        if(isFIFO)
81                list_add_last(&el->tbl[prio].root, &event->e_list);
82        else
83                list_add_first(&el->tbl[prio].root, &event->e_list);
84
85        el->tbl[prio].count ++;
86        el->prio = (!(el->flags & EVENT_PENDING) || (el->prio > prio)) ? prio : el->prio;
87        el->flags |= EVENT_PENDING;
88
89        cpu_restore_irq(irq_state);
90
91#if CONFIG_SHOW_LOCAL_EVENTS
92        isr_dmsg(INFO, "%s: cpu %d, prio %d, el->prio %d [%d]\n", 
93                 __FUNCTION__, 
94                 cpu_get_id(), 
95                 prio, 
96                 el->prio,
97                 cpu_time_stamp());
98#endif
99}
100
101#if 0
102static EVENT_HANDLER(re_send_backoff_handler)
103{
104        uint_t cpu_gid;
105 
106        cpu_gid = (uint_t) event_get_argument(event);
107 
108        event_restore(event);
109 
110        event_send(event, cpu_gid);
111
112        printk(INFO, "INFO: %s, cpu %d, event %x sent to cpu_gid %d [%d]\n",
113               __FUNCTION__,
114               cpu_get_id(),
115               event,
116               cpu_gid,
117               cpu_time_stamp());
118 
119        return 0;
120}
121
122static error_t __attribute__((noinline)) re_send_backoff(struct event_s *event,
123                                                         uint_t cpu_gid,
124                                                         uint_t tm_stamp)
125{
126        struct cpu_s *cpu;
127        uint_t tm_now;
128        uint_t irq_state;
129
130        tm_now = cpu_time_stamp();
131        cpu    = current_cpu;
132
133        if((tm_now - tm_stamp) < cpu_get_ticks_period(cpu))
134                return EAGAIN;
135
136        event_backup(event);
137 
138        event_set_priority(event, E_CHR);
139        event_set_handler(event, re_send_backoff_handler);
140        event_set_argument(event, (void*)cpu_gid);
141
142        cpu_disable_all_irq(&irq_state);
143        local_event_send(event, &cpu->le_listner, false);
144        cpu_restore_irq(irq_state);
145
146        printk(INFO, "INFO: %s, cpu %d, event %x sent to cpu_gid %d [%d]\n",
147               __FUNCTION__,
148               cpu->gid,
149               event,
150               cpu_gid,
151               tm_now);
152
153        return 0;
154}
155
156/** This is the only function that handle remote data **/
157static void remote_event_send(struct event_s *event,
158                                struct event_listner_s *el,
159                                uint_t cid, uint_t cpu_gid)
160{
161        error_t retry;
162        uint_t tm_stamp;
163        uint_t prio;
164
165        tm_stamp = cpu_time_stamp();
166        prio     = event_get_priority(event);
167
168        while((retry = event_fifo_put(&el->tbl[prio].fifo, cid, event)) != 0)
169        {
170                retry = re_send_backoff(event, cpu_gid, tm_stamp);
171   
172                if(retry == 0)
173                        break;
174        }
175
176
177#if 1
178        bool_t isPending;
179        uint_t flags = remote_lw((void*)&el->flags, cid);
180        isPending = (flags & EVENT_PENDING) ? true : false;
181
182        remote_sw((void*)&el->flags, cid, flags | EVENT_PENDING);
183        cpu_wbflush();
184        pmm_cache_flush_raddr((vma_t) &el->flags, cid, PMM_DATA);
185
186        if((prio < E_FUNC) && (isPending == false))
187        {
188                (void)arch_cpu_send_ipi(cpu_gid);
189        }
190#else
191
192        if((prio < E_FUNC))
193        {
194                (void)arch_cpu_send_ipi(cpu_gid);
195        }
196#endif
197}
198#endif
199
200/* must be called with all irq disabled */
201void event_send(struct event_s *event, uint_t cpu_gid)
202{
203        uint_t cid = arch_cpu_cid(cpu_gid);
204        uint_t lid = arch_cpu_lid(cpu_gid);
205
206        if (cid != current_cid)
207        {
208                PANIC("event not local cid [cpu %d, cid %d, cycle %u]\n", 
209                      cpu_get_id(), 
210                      cid,
211                      cpu_time_stamp());
212        }
213       
214        local_event_send(event, &cpu_lid2ptr(lid)->le_listner, true);
215}
216
217
218static void local_event_listner_notify(struct event_listner_s *el)
219{
220        register struct event_s *event;
221        register uint_t count;
222        register uint_t start_prio;
223        register uint_t current_prio;
224
225#if CONFIG_SHOW_LOCAL_EVENTS
226        register uint_t cntr;
227#endif
228 
229        count = 0;
230        assert((el->flags & EVENT_PENDING) && "event_notify is called but no event is pending");
231
232        el->flags   &= ~EVENT_PENDING;
233        start_prio   = el->prio ++;
234        current_prio = start_prio;
235
236        while(current_prio < E_PRIO_NR)
237        {
238                if(el->prio <= start_prio)
239                {
240                        start_prio   = el->prio ++;
241                        current_prio = start_prio;
242                }
243
244                while(el->tbl[current_prio].count != 0)
245                {
246                        assert(!(list_empty(&el->tbl[current_prio].root)) && "pending event queue is empty");
247
248                        event = list_first(&el->tbl[current_prio].root, struct event_s, e_list);
249                        //printk(INFO, "%d Handling event %p with prio %d\n", current_cpu->gid, event, current_prio);
250                        list_unlink(&event->e_list);
251     
252                        el->tbl[current_prio].count --;
253     
254                        cpu_enable_all_irq(NULL);
255                        event_get_handler(event)(event);         /* el->prio can be changed */
256                        count ++;
257
258#if CONFIG_SHOW_LOCAL_EVENTS
259                        cntr ++;
260#endif
261
262                        cpu_disable_all_irq(NULL);
263                }
264
265#if CONFIG_SHOW_LOCAL_EVENTS   
266                cpu_enable_all_irq(NULL);
267                if(cntr)
268                {
269                        printk(INFO, "INFO: cpu %d, %d pending events of priority %d have been Delivered [ %u ]\n",
270                               cpu_get_id(),
271                               cntr, 
272                               current_prio, 
273                               cpu_time_stamp());
274                }
275                cntr = 0;
276                cpu_disable_all_irq(NULL);
277#endif
278   
279                current_prio ++;
280        }
281
282        el->count += count;
283}
284
285
286#if 0
287static void remote_event_listner_notify(struct event_listner_s *el)
288{
289        struct event_listner_s *local_el;
290        struct event_s *event;
291        event_prio_t current_prio;
292        uint_t irq_state;
293        uint_t count;
294        error_t err;
295        uint_t cid;
296 
297        local_el = &current_cpu->le_listner;
298        cid = current_cid;
299        count    = 0;
300
301        do
302        {
303                el->flags &= ~EVENT_PENDING;
304                cpu_wbflush();
305                pmm_cache_flush_vaddr((vma_t)&el->flags, PMM_DATA);
306
307                cpu_disable_all_irq(&irq_state);
308
309                for(current_prio = E_CLK; current_prio < E_PRIO_NR; current_prio++, count++)
310                {
311                        while((err = event_fifo_get(&el->tbl[current_prio].fifo, cid, (void**)&event)) == 0)
312                                local_event_send(event, local_el, false);//event is local
313                }
314
315                cpu_restore_irq(irq_state);
316                el->count += count;
317
318        }while(el->flags & EVENT_PENDING);
319}
320#endif
321
322/* must be called with all irq disabled */
323void event_listner_notify(struct event_listner_s *el)
324{
325        local_event_listner_notify(el);
326}
327
328
329void* thread_event_manager(void *arg)
330{
331        struct thread_s *this;
332        struct cpu_s *cpu;
333        uint_t irq_state;
334
335        cpu_enable_all_irq(NULL);
336 
337        this = current_thread;
338        cpu  = current_cpu;
339
340        thread_preempt_disable(this);
341
342        while(1)
343        {
344#if 0
345                printk(INFO, "INFO: Event Handler on CPU %d, event is le pending %d [%d,%d]\n",
346                       cpu->gid,
347                       event_is_pending(&cpu->le_listner),
348                       cpu_time_stamp(),
349                       cpu_get_ticks(cpu));
350#endif
351   
352                cpu_disable_all_irq(&irq_state);
353
354                if(event_is_pending(&cpu->le_listner))
355                        event_listner_notify(&cpu->le_listner);
356   
357                wait_on(&this->info.wait_queue, WAIT_ANY);
358
359                sched_sleep(this);
360
361                cpu_restore_irq(irq_state);
362        }
363
364        return NULL;
365}
Note: See TracBrowser for help on using the repository browser.