1February 2002: 2 3The mDNSResponder code has a slight architectural change to improve 4efficiency. 5 6The mDNSResponder code previously called ScheduleNextTask() after every 7operation, to calculate the time at which it needed to be called back to 8perform its next timed operation. When the workload is light, and 9protocol operations are rare and far apart, this makes sense. 10 11However, on networks where there is a lot of mDNS traffic (or the CPU is 12slow), this leads to the following anomolous behaviour: mDNSResponder 13spends a lot of CPU time working out what to do next, when what it needs 14to do next should be obvious: Finish processing the big backlog of 15packets that have been received. 16 17To remedy this, mDNSResponder now only executes ScheduleNextTask() when 18there is no other obvious work waiting to be done. However, the 19mDNSResponder code does not have direct access to this knowledge. Only 20the platform layer below knows whether there are packets waiting to be 21processed. Only the client layer above knows whether it is in the 22process of performing a long sequence of back-to-back mDNS API calls. 23 24This means that the new architecture places an additional responsibility 25on the client layer and/or platform support layer. As long as they have 26immediate work to do, they should call the appropriate mDNSCore routines 27to accomplish that work. With each call, mDNSCore will do only what it 28immediately has to do to satisfy the call. Any optional work will be 29deferred. As soon as there is no more immediate work to do, the calling 30layer MUST call mDNS_Execute(). Failure to call mDNS_Execute() will lead 31to unreliable or incorrect operation. 32 33The value returned from mDNS_Execute() is the next time (in absolute 34platform time units) at which mDNS_Execute() MUST be called again to 35perform its next necessary operation (e.g. transmitting its next 36scheduled query packet, etc.) Note that the time returned is an absolute 37time, not the time *interval* between now and the next required call. 38For OS APIs that work in terms of intervals instead of absolute times, 39mDNSPlatformTimeNow() must be subtracted from the absolute time to get 40the interval between now and the next event. 41 42In a single-threaded application using a blocking select() call as its 43main synchronization point, this means that you should call 44mDNS_Execute() before calling select(), and the timeout value you pass 45to select() MUST NOT be larger than that indicated by the result 46returned from mDNS_Execute(). After the blocking select() call returns, 47you should do whatever work you have to do, and then, if mDNS packets 48were received, or mDNS API calls were made, be sure to call 49mDNS_Execute() again, and if necessary adjust your timeout value 50accordingly, before going back into the select() call. 51 52In an asynchronous or interrupt-driven application, there are three 53places that should call mDNS_Execute(): 54 551. After delivering received packets, the platform support layer should 56call mDNS_Execute(), and use the value returned to set the platform 57callback timer to fire at the indicated time. 58 592. After making any mDNS API call or series of calls, the client layer 60should call mDNS_Execute(), and use the value returned to set the 61platform callback timer to fire at the indicated time. 62 633. When the platform callback timer fires, it should call mDNS_Execute() 64(to allow mDNSCore to perform its necessary work) and then the timer 65routine use the result returned to reset itself to fire at the right 66time for the next scheduled event. 67