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

Last change on this file since 375 was 355, checked in by max@…, 7 years ago

Remove unused include.

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