Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
event.c
00001 /* 00002 * Copyright (c) 2014-2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #include <string.h> 00017 #include "ns_types.h" 00018 #include "ns_list.h" 00019 #include "eventOS_event.h" 00020 #include "eventOS_scheduler.h" 00021 #include "timer_sys.h" 00022 #include "nsdynmemLIB.h" 00023 #include "ns_timer.h" 00024 #include "event.h" 00025 #include "platform/arm_hal_interrupt.h" 00026 00027 00028 typedef struct arm_core_tasklet { 00029 int8_t id; /**< Event handler Tasklet ID */ 00030 void (*func_ptr)(arm_event_s *); 00031 ns_list_link_t link; 00032 } arm_core_tasklet_t; 00033 00034 static NS_LIST_DEFINE(arm_core_tasklet_list, arm_core_tasklet_t, link); 00035 static NS_LIST_DEFINE(event_queue_active, arm_event_storage_t, link); 00036 static NS_LIST_DEFINE(free_event_entry, arm_event_storage_t, link); 00037 00038 // Statically allocate initial pool of events. 00039 #define STARTUP_EVENT_POOL_SIZE 10 00040 static arm_event_storage_t startup_event_pool[STARTUP_EVENT_POOL_SIZE]; 00041 00042 /** Curr_tasklet tell to core and platform which task_let is active, Core Update this automatic when switch Tasklet. */ 00043 int8_t curr_tasklet = 0; 00044 00045 00046 static arm_core_tasklet_t *tasklet_dynamically_allocate(void); 00047 static arm_event_storage_t *event_dynamically_allocate(void); 00048 static arm_event_storage_t *event_core_get(void); 00049 static void event_core_write(arm_event_storage_t *event); 00050 00051 static arm_core_tasklet_t *event_tasklet_handler_get(uint8_t tasklet_id) 00052 { 00053 ns_list_foreach(arm_core_tasklet_t, cur, &arm_core_tasklet_list) { 00054 if (cur->id == tasklet_id) { 00055 return cur; 00056 } 00057 } 00058 return NULL; 00059 } 00060 00061 bool event_tasklet_handler_id_valid(uint8_t tasklet_id) 00062 { 00063 return event_tasklet_handler_get(tasklet_id); 00064 } 00065 00066 // XXX this can return 0, but 0 seems to mean "none" elsewhere? Or at least 00067 // curr_tasklet is reset to 0 in various places. 00068 static int8_t tasklet_get_free_id(void) 00069 { 00070 /*(Note use of uint8_t to avoid overflow if we reach 0x7F)*/ 00071 for (uint8_t i = 0; i <= INT8_MAX; i++) { 00072 if (!event_tasklet_handler_get(i)) { 00073 return i; 00074 } 00075 } 00076 return -1; 00077 } 00078 00079 00080 int8_t eventOS_event_handler_create(void (*handler_func_ptr)(arm_event_s *), uint8_t init_event_type) 00081 { 00082 arm_event_storage_t *event_tmp; 00083 00084 // XXX Do we really want to prevent multiple tasklets with same function? 00085 ns_list_foreach(arm_core_tasklet_t, cur, &arm_core_tasklet_list) { 00086 if (cur->func_ptr == handler_func_ptr) { 00087 return -1; 00088 } 00089 } 00090 00091 //Allocate new 00092 arm_core_tasklet_t *new = tasklet_dynamically_allocate(); 00093 if (!new) { 00094 return -2; 00095 } 00096 00097 event_tmp = event_core_get(); 00098 if (!event_tmp) { 00099 ns_dyn_mem_free(new); 00100 return -2; 00101 } 00102 00103 //Fill in tasklet; add to list 00104 new->id = tasklet_get_free_id(); 00105 new->func_ptr = handler_func_ptr; 00106 ns_list_add_to_end(&arm_core_tasklet_list, new); 00107 00108 //Queue "init" event for the new task 00109 event_tmp->data.receiver = new->id; 00110 event_tmp->data.sender = 0; 00111 event_tmp->data.event_type = init_event_type; 00112 event_tmp->data.event_data = 0; 00113 event_core_write(event_tmp); 00114 00115 return new->id; 00116 } 00117 00118 int8_t eventOS_event_send(const arm_event_t *event) 00119 { 00120 if (event_tasklet_handler_get(event->receiver)) { 00121 arm_event_storage_t *event_tmp = event_core_get(); 00122 if (event_tmp) { 00123 event_tmp->data = *event; 00124 event_core_write(event_tmp); 00125 return 0; 00126 } 00127 } 00128 return -1; 00129 } 00130 00131 void eventOS_event_send_user_allocated(arm_event_storage_t *event) 00132 { 00133 event->allocator = ARM_LIB_EVENT_USER; 00134 event_core_write(event); 00135 } 00136 00137 void eventOS_event_send_timer_allocated(arm_event_storage_t *event) 00138 { 00139 event->allocator = ARM_LIB_EVENT_TIMER; 00140 event_core_write(event); 00141 } 00142 00143 void eventOS_event_cancel_critical(arm_event_storage_t *event) 00144 { 00145 ns_list_remove(&event_queue_active, event); 00146 } 00147 00148 static arm_event_storage_t *event_dynamically_allocate(void) 00149 { 00150 arm_event_storage_t *event = ns_dyn_mem_temporary_alloc(sizeof(arm_event_storage_t)); 00151 if (event) { 00152 event->allocator = ARM_LIB_EVENT_DYNAMIC; 00153 } 00154 return event; 00155 } 00156 00157 static arm_core_tasklet_t *tasklet_dynamically_allocate(void) 00158 { 00159 return ns_dyn_mem_alloc(sizeof(arm_core_tasklet_t)); 00160 } 00161 00162 arm_event_storage_t *event_core_get(void) 00163 { 00164 arm_event_storage_t *event; 00165 platform_enter_critical(); 00166 event = ns_list_get_first(&free_event_entry); 00167 if (event) { 00168 ns_list_remove(&free_event_entry, event); 00169 } else { 00170 event = event_dynamically_allocate(); 00171 } 00172 if (event) { 00173 event->data.data_ptr = NULL; 00174 event->data.priority = ARM_LIB_LOW_PRIORITY_EVENT; 00175 } 00176 platform_exit_critical(); 00177 return event; 00178 } 00179 00180 void event_core_free_push(arm_event_storage_t *free) 00181 { 00182 free->state = ARM_LIB_EVENT_UNQUEUED; 00183 00184 switch (free->allocator) { 00185 case ARM_LIB_EVENT_STARTUP_POOL: 00186 platform_enter_critical(); 00187 ns_list_add_to_start(&free_event_entry, free); 00188 platform_exit_critical(); 00189 break; 00190 case ARM_LIB_EVENT_DYNAMIC: 00191 // Free all dynamically allocated events. 00192 ns_dyn_mem_free(free); 00193 break; 00194 case ARM_LIB_EVENT_TIMER: 00195 // Hand it back to the timer system 00196 timer_sys_event_free(free); 00197 break; 00198 case ARM_LIB_EVENT_USER: 00199 default: 00200 break; 00201 } 00202 } 00203 00204 00205 static arm_event_storage_t *event_core_read(void) 00206 { 00207 platform_enter_critical(); 00208 arm_event_storage_t *event = ns_list_get_first(&event_queue_active); 00209 if (event) { 00210 event->state = ARM_LIB_EVENT_RUNNING; 00211 ns_list_remove(&event_queue_active, event); 00212 } 00213 platform_exit_critical(); 00214 return event; 00215 } 00216 00217 void event_core_write(arm_event_storage_t *event) 00218 { 00219 platform_enter_critical(); 00220 bool added = false; 00221 ns_list_foreach(arm_event_storage_t, event_tmp, &event_queue_active) { 00222 // note enum ordering means we're checking if event_tmp is LOWER priority than event 00223 if (event_tmp->data.priority > event->data.priority) { 00224 ns_list_add_before(&event_queue_active, event_tmp, event); 00225 added = true; 00226 break; 00227 } 00228 } 00229 if (!added) { 00230 ns_list_add_to_end(&event_queue_active, event); 00231 } 00232 event->state = ARM_LIB_EVENT_QUEUED; 00233 00234 /* Wake From Idle */ 00235 platform_exit_critical(); 00236 eventOS_scheduler_signal(); 00237 } 00238 00239 // Requires lock to be held 00240 arm_event_storage_t *eventOS_event_find_by_id_critical(uint8_t tasklet_id, uint8_t event_id) 00241 { 00242 ns_list_foreach(arm_event_storage_t, cur, &event_queue_active) { 00243 if (cur->data.receiver == tasklet_id && cur->data.event_id == event_id) { 00244 return cur; 00245 } 00246 } 00247 00248 return NULL; 00249 } 00250 00251 /** 00252 * 00253 * \brief Initialize Nanostack Core. 00254 * 00255 * Function Initialize Nanostack Core, Socket Interface,Buffer memory and Send Init event to all Tasklett which are Defined. 00256 * 00257 */ 00258 void eventOS_scheduler_init(void) 00259 { 00260 /* Reset Event List variables */ 00261 ns_list_init(&free_event_entry); 00262 ns_list_init(&event_queue_active); 00263 ns_list_init(&arm_core_tasklet_list); 00264 00265 //Add first 10 entries to "free" list 00266 for (unsigned i = 0; i < (sizeof(startup_event_pool) / sizeof(startup_event_pool[0])); i++) { 00267 startup_event_pool[i].allocator = ARM_LIB_EVENT_STARTUP_POOL; 00268 ns_list_add_to_start(&free_event_entry, &startup_event_pool[i]); 00269 } 00270 00271 /* Init Generic timer module */ 00272 timer_sys_init(); //initialize timer 00273 /* Set Tasklett switcher to Idle */ 00274 curr_tasklet = 0; 00275 00276 } 00277 00278 int8_t eventOS_scheduler_get_active_tasklet(void) 00279 { 00280 return curr_tasklet; 00281 } 00282 00283 void eventOS_scheduler_set_active_tasklet(int8_t tasklet) 00284 { 00285 curr_tasklet = tasklet; 00286 } 00287 00288 int eventOS_scheduler_timer_stop(void) 00289 { 00290 timer_sys_disable(); 00291 if (ns_timer_sleep() != 0) { 00292 return 1; 00293 } 00294 return 0; 00295 } 00296 00297 int eventOS_scheduler_timer_synch_after_sleep(uint32_t sleep_ticks) 00298 { 00299 //Update MS to 10ms ticks 00300 sleep_ticks /= 10; 00301 sleep_ticks++; 00302 system_timer_tick_update(sleep_ticks); 00303 if (timer_sys_wakeup() == 0) { 00304 return 0; 00305 } 00306 return -1; 00307 } 00308 00309 /** 00310 * 00311 * \brief Infinite Event Read Loop. 00312 * 00313 * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep 00314 * 00315 */ 00316 bool eventOS_scheduler_dispatch_event(void) 00317 { 00318 curr_tasklet = 0; 00319 00320 arm_event_storage_t *cur_event = event_core_read(); 00321 if (!cur_event) { 00322 return false; 00323 } 00324 00325 curr_tasklet = cur_event->data.receiver; 00326 00327 arm_core_tasklet_t *tasklet = event_tasklet_handler_get(curr_tasklet); 00328 /* Do not bother with check for NULL - tasklets cannot be deleted, 00329 * and user-facing API eventOS_event_send() has already checked the tasklet 00330 * exists, so there is no possible issue there. 00331 * 00332 * For eventOS_event_send_user_allocated(), it would be a non-recoverable 00333 * error to not deliver the message - we have to have a receiver to pass 00334 * ownership to. If the lookup fails, let it crash. We want the send call 00335 * itself to return void to simplify logic. 00336 */ 00337 00338 /* Tasklet Scheduler Call */ 00339 tasklet->func_ptr(&cur_event->data); 00340 event_core_free_push(cur_event); 00341 00342 /* Set Current Tasklet to Idle state */ 00343 curr_tasklet = 0; 00344 00345 return true; 00346 } 00347 00348 void eventOS_scheduler_run_until_idle(void) 00349 { 00350 while (eventOS_scheduler_dispatch_event()); 00351 } 00352 00353 /** 00354 * 00355 * \brief Infinite Event Read Loop. 00356 * 00357 * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep 00358 * 00359 */ 00360 NS_NORETURN void eventOS_scheduler_run(void) 00361 { 00362 while (1) { 00363 if (!eventOS_scheduler_dispatch_event()) { 00364 eventOS_scheduler_idle(); 00365 } 00366 } 00367 } 00368 00369 void eventOS_cancel(arm_event_storage_t *event) 00370 { 00371 if (!event) { 00372 return; 00373 } 00374 00375 platform_enter_critical(); 00376 00377 /* 00378 * Notify timer of cancellation. 00379 */ 00380 if (event->allocator == ARM_LIB_EVENT_TIMER) { 00381 timer_sys_event_cancel_critical(event); 00382 } 00383 00384 /* 00385 * Remove event from the list, 00386 * Only queued can be removed, unqued are either timers or stale pointers 00387 * RUNNING cannot be removed, we are currenly "in" that event. 00388 */ 00389 if (event->state == ARM_LIB_EVENT_QUEUED) { 00390 eventOS_event_cancel_critical(event); 00391 } 00392 00393 /* 00394 * Push back to "free" state 00395 */ 00396 if (event->state != ARM_LIB_EVENT_RUNNING) { 00397 event_core_free_push(event); 00398 } 00399 00400 platform_exit_critical(); 00401 }
Generated on Tue Jul 12 2022 12:43:58 by
