@@ -152,6 +152,32 @@ static void scheduler_process_native_signal_messages(Context *ctx)
152152 }
153153}
154154
155+ static Context * scheduler_first_runnable_ready (GlobalContext * global )
156+ {
157+ Context * result = NULL ;
158+ SMP_SPINLOCK_LOCK (& global -> processes_spinlock );
159+ // Pick first ready which is not running.
160+ struct ListHead * next_ready = list_first (& global -> ready_processes );
161+ while (next_ready != & global -> ready_processes ) {
162+ result = GET_LIST_ENTRY (next_ready , Context , processes_list_head );
163+ if (!(result -> flags & Running )) {
164+ list_remove (next_ready );
165+ context_update_flags (result , ~Ready , Running );
166+ if (result -> native_handler ) {
167+ // Native handlers are marked as waiting
168+ list_append (& global -> waiting_processes , next_ready );
169+ } else {
170+ list_append (& global -> running_processes , next_ready );
171+ }
172+ break ;
173+ }
174+ next_ready = next_ready -> next ;
175+ result = NULL ;
176+ }
177+ SMP_SPINLOCK_UNLOCK (& global -> processes_spinlock );
178+ return result ;
179+ }
180+
155181static Context * scheduler_run0 (GlobalContext * global )
156182{
157183 // This function should return a new process to run.
@@ -209,6 +235,13 @@ static Context *scheduler_run0(GlobalContext *global)
209235 return NULL ;
210236 }
211237 if (!is_waiting ) {
238+ // If a process is ready, process it instead of waking up
239+ // the poller scheduler
240+ result = scheduler_first_runnable_ready (global );
241+ if (result != NULL ) {
242+ break ;
243+ }
244+
212245 // Before entering the condition variable, signal the poll events
213246 // so the thread polling on events can check the ready queue.
214247 sys_signal (global );
@@ -232,41 +265,35 @@ static Context *scheduler_run0(GlobalContext *global)
232265 int32_t wait_timeout = update_timer_list (global );
233266 SMP_SPINLOCK_UNLOCK (& global -> timer_spinlock );
234267
235- SMP_SPINLOCK_LOCK (& global -> processes_spinlock );
236- // Pick first ready which is not running.
237- struct ListHead * next_ready = list_first (& global -> ready_processes );
238- while (next_ready != & global -> ready_processes ) {
239- result = GET_LIST_ENTRY (next_ready , Context , processes_list_head );
240- if (!(result -> flags & Running )) {
241- list_remove (next_ready );
242- context_update_flags (result , ~Ready , Running );
243- if (result -> native_handler ) {
244- // Native handlers are marked as waiting
245- list_append (& global -> waiting_processes , next_ready );
246- } else {
247- list_append (& global -> running_processes , next_ready );
248- }
249- break ;
250- }
251- next_ready = next_ready -> next ;
252- result = NULL ;
268+ if (result == NULL ) {
269+ result = scheduler_first_runnable_ready (global );
253270 }
254- SMP_SPINLOCK_UNLOCK (& global -> processes_spinlock );
255271
256- if (result == NULL && !global -> scheduler_stop_all ) {
257- sys_poll_events (global , wait_timeout );
258- } else {
259- sys_poll_events (global , SYS_POLL_EVENTS_DO_NOT_WAIT );
272+ // Only the poller scheduler drives the event loop.
273+ #ifndef AVM_NO_SMP
274+ if (is_waiting ) {
275+ #endif
276+ if (result == NULL && !global -> scheduler_stop_all ) {
277+ // The poller may block waiting for events.
278+ sys_poll_events (global , wait_timeout );
279+ } else {
280+ sys_poll_events (global , SYS_POLL_EVENTS_DO_NOT_WAIT );
281+ }
282+ #ifndef AVM_NO_SMP
260283 }
284+ #endif
261285#ifdef AVM_TASK_DRIVER_ENABLED
262286 globalcontext_process_task_driver_queues (global );
263287#endif
264288 SMP_MUTEX_LOCK (global -> schedulers_mutex );
265289 } while (result == NULL );
266290
267291#ifndef AVM_NO_SMP
268- global -> waiting_scheduler = false;
269- smp_condvar_signal (global -> schedulers_cv );
292+ // Only the polling scheduler relinquishes the poller role.
293+ if (is_waiting ) {
294+ global -> waiting_scheduler = false;
295+ smp_condvar_signal (global -> schedulers_cv );
296+ }
270297 SMP_MUTEX_UNLOCK (global -> schedulers_mutex );
271298#endif
272299
@@ -356,6 +383,12 @@ static void scheduler_make_ready(Context *ctx)
356383 return ;
357384 }
358385 list_remove (& ctx -> processes_list_head );
386+ // Move to ready queue (from waiting or running)
387+ // The process may be running (it would be signaled), so mark it
388+ // as ready
389+ context_update_flags (ctx , ~NoFlags , Ready );
390+ list_append (& global -> ready_processes , & ctx -> processes_list_head );
391+ SMP_SPINLOCK_UNLOCK (& global -> processes_spinlock );
359392#ifndef AVM_NO_SMP
360393 if (SMP_MUTEX_TRYLOCK (global -> schedulers_mutex )) {
361394 // Start a new scheduler if none are going to take this process.
@@ -366,17 +399,6 @@ static void scheduler_make_ready(Context *ctx)
366399 global -> running_schedulers ++ ;
367400 smp_scheduler_start (global );
368401 }
369- SMP_MUTEX_UNLOCK (global -> schedulers_mutex );
370- }
371- #endif
372- // Move to ready queue (from waiting or running)
373- // The process may be running (it would be signaled), so mark it
374- // as ready
375- context_update_flags (ctx , ~NoFlags , Ready );
376- list_append (& global -> ready_processes , & ctx -> processes_list_head );
377- SMP_SPINLOCK_UNLOCK (& global -> processes_spinlock );
378- #ifndef AVM_NO_SMP
379- if (SMP_MUTEX_TRYLOCK (global -> schedulers_mutex )) {
380402 if (global -> waiting_scheduler ) {
381403 sys_signal (global );
382404 }
0 commit comments