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