1. As of now, members of the group have made additional requests for timeout in Skynet. Currently the timer provided by Skynet is a countdown form, and once the timer is set, it cannot be revoked (at least for the current implementation), and then the CB is called
It has recently been suggested that it is possible to support the function of the undo timer, but the cloud insists: "The framework should only provide the essential features that can be removed from what has been achieved with existing features."
2. Why do we say pseudo-Cancel timer?
In Skynet, when Skynet.timeout (time, CB) is called, it goes into skynet_timer.c management, and then, after that time, the message is placed on the calling service's message queue, waiting for the callback function to process.
The real cancellation timer is when the party calls the cancel timer interface, stops the countdown and deletes the task from somewhere, as if nothing had happened.
Then the pseudo-cancellation is the countdown to continue execution, only when the callback function execution after the countdown, not the callback registered when the call timer, but the change of the callback, this callback does not do anything, thereby implementing pseudo-cancellation.
3. The idea of pseudo-cancellation timer
First look at the Skynet.timeout ().
function Skynet.timeout (Ti, func) = C.intcommand ("TIMEOUT", Ti) assert (session) = co_create (func) = = Nil )= Co return sessionend
1) use "TIMEOUT" command to start this countdown, and return a session, and then use the back function to create a co-process, create the following code:
Local functionco_create (f)LocalCO =Table.remove(Coroutine_pool)ifCO = =Nil ThenCo=coroutine.create(function(...) F (...) while true DoF=Nilcoroutine_pool[#coroutine_pool +1] =Co F= Coroutine_yield"EXIT"f (Coroutine_yield ())End End) ElseCoroutine_resume (Co, F)End returnCoEnd
For the pool in this virtual machine, Coroutine_pool will only be used in this function, that is, if the pool is empty, then use F to create a new co-process and put it in the pool, if there is a co-re-registration callback function F.
2) use session_id_coroutine[session] = Co to save the relationship between the session and Co, and when the countdown is over, the session will be based on Co. The timeout function ends here, and then it looks like the framework can be used to implement the callback after the countdown is over. Seems to have done nothing, the real mystery in
Local session = C.intcommand ("TIMEOUT", TI).
The hand has the source code can directly follow in, see what exactly did.
So where is the call to the callback? In Skynet.draw_dispatch_message (...) In
functionskynet.dispatch_message (...) LocalSUCC, err =Pcall(Raw_dispatch_message,...) while true Do LocalKey,co =Next(Fork_queue)ifCO = =Nil Then Break EndFork_queue[key]=Nil LocalFORK_SUCC, Fork_err =Pcall(Suspend,co,coroutine_resume (CO))if notFork_succ Then ifSucc Thensucc=falseErr=ToString(Fork_err)ElseErr=ToString(ERR):"\ n"..ToString(Fork_err)End End End assert(SUCC,ToString(err))EndLocal functionRaw_dispatch_message (prototype, MSG, SZ, session, source)--Skynet. Ptype_response = 1, read skynet.h ifPrototype = =1 Then LocalCO =Session_id_coroutine[session]ifCO = =" Break" ThenSession_id_coroutine[session]=Nil ElseIfCO = =Nil Then Print("prototype, MSG, SZ, session, Source:", prototype, MSG, SZ, session, Source) Unknown_response (session, source, MSG, SZ)ElseSession_id_coroutine[session]=Nilsuspend (CO, Coroutine_resume (CO,true, MSG, SZ)) End Else Localp =Proto[prototype]ifp = =Nil Then ifSession ~=0 Thenc.send (source, Skynet. Ptype_error, Session,"") ElseUnknown_request (session, source, MSG, SZ, prototype)End return End Localf =P.dispatchifF Then Localref =Watching_service[source]ifRef ThenWatching_service[source]= ref +1 ElseWatching_service[source]=1 End LocalCO =co_create (f) Session_coroutine_id[co]=session Session_coroutine_address[co]=Source Suspend (CO, Coroutine_resume (CO, Session,source, p.Unpack(MSG,SZ))) ElseUnknown_request (session, source, MSG, SZ, proto[prototype].name)End EndEnd
The logic of the yellow code is executed when the countdown is complete:
Session_id_coroutine[session] = Nil
suspend (CO, Coroutine_resume (CO, true, MSG, SZ))
At this point the Co is obtained from the session, and the Co is the callback process.
As mentioned earlier, to cancel is a co that is replaced with nothing until the time of the CO is done. The key to replacement: 1. Desession;2 The first time timeout, regenerate a co. Both of these points can be implemented in Skynet.lua, with the following code:
Local functionREMOVE_TIMEOUT_CB (...)EndfunctionSkynet.remove_timeout (session)LocalCO =co_create (REMOVE_TIMEOUT_CB)assert(Session_id_coroutine[session] ~=Nil) Session_id_coroutine[session]=CoEndfunctionskynet.timeout (Ti, func)LocalSession = C.intcommand ("TIMEOUT", TI)assert(session)LocalCO =Co_create (func)assert(Session_id_coroutine[session] = =Nil) Session_id_coroutine[session]=CoreturnSessionEnd
As you can see, the Skynet.remove_timeout and SKYNET.REMOVE_TIMEOUT_CB () are added, and the obtained session is returned in Skynet.timeout (). The code is very simple, just follow the previous ideas to achieve.
4. Test the code:
Local session = Skynet.timeout ("test Timeout 10 end) Skynet.remove_timeout (session) Skynet.timeout (function Print("test timeout"end)
5. Test process:
1) Modify the Skynet.lua, add Skynet.remove_timeout and SKYNET.REMOVE_TIMEOUT_CB (), and make the Skynet.timeout return the resulting session.
2) Modify the configuration file Config,start = "Testtimer" To change the start script to test Testtimmer, where the test will be performed.
3) Use the top three test code in Skynet.start in Testtimer.lua, or write it yourself to get the results.
To this, a skyent pseudo-cancellation timer was implemented. Of course can be passed to similar c. Initcommand ("TIMEOUT", T1) in this form, the implementation of their own "remove_timeout" command, only such changes in more places, but can achieve a complete cancellation.
A temporary cancellation was implemented today and a new command is being created to completely cancel. It is hereby recorded that you are welcome to correct and advise.
Skynet's pseudo-Cancel timer