1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859(** the queue of actions to be executed before everything in the main loop *)(* NOTE: if some actions take too much time, the remaining ones are postponed to
next iteration of the main loop. *)(* FIFO queue: order of actions is preserved *)(* Warning: the first Sync execution is done slightly before the main loop, with
a little more time... Make sure that's no problem. *)openB_utilsmoduleTime=B_timemoduleVar=B_varmoduleTrigger=B_triggertypeaction=unit->unitletqueue:(actionQueue.t)Var.t=Var.create(Queue.create())letis_empty()=Queue.is_empty(Var.getqueue)(* Warning: a Sync action cannot push another Sync action, because it will wait
forever the release of the mutex *)(* TODO: add a test of this using Mutex.try_lock *)letpushaction=printddebug_thread"Sync push action";Var.protect_fnqueue(Queue.pushaction);Trigger.push_action()(* If [o] is None, Sync-compute the value with [future] and apply it to [f] *)letoptionofuturef=matchowith|Somex->fx|None->push(fun()->letx=future()infx)(* Returns true if some action was executed *)(* We assume that the whole process does not need to be mutex protected. It
should be OK if other treads are adding to the Queue, as long as we (the main
thread) are the only ones popping from the queue. *)letexecutetimeout=ifis_empty()thenfalse(* a quick test in order to avoid lock *)elselett=Time.now()inletrecloop()=ifVar.with_protectqueueQueue.is_emptythen()(* we exit *)elseifTime.(now()-t>timeout)then(* we exit but also send a action event to finish the rest of the
queue at next iteration. *)beginprintddebug_thread"Didn't have time to finish Sync queue.";Trigger.push_action()endelseletaction=Var.with_protectqueueQueue.popinprintddebug_thread"Popping one action from the Sync Queue.";action();loop();inloop();true