+ // Note: We want to allow our DNS-SD operation to be stopped from other threads, so we have to
+ // block waiting for data *outside* the synchronized section. Because we're doing this unsynchronized
+ // we have to write some careful code. Suppose our DNS-SD operation is stopped from some other thread,
+ // and then immediately afterwards that thread (or some third, unrelated thread) starts a new DNS-SD
+ // operation. The Unix kernel always allocates the lowest available file descriptor to a new socket,
+ // so the same file descriptor is highly likely to be reused for the new operation, and if our old
+ // stale ServiceThread accidentally consumes bytes off that new socket we'll get really messed up.
+ // To guard against that, before calling ProcessResults we check to ensure that our
+ // fNativeContext has not been deleted, which is a telltale sign that our operation was stopped.
+ // After calling ProcessResults we check again, because it's extremely common for callback
+ // functions to stop their own operation and start others. For example, a resolveListener callback
+ // may well stop the resolve and then start a QueryRecord call to monitor the TXT record.
+ //
+ // The remaining risk is that between our checking fNativeContext and calling ProcessResults(),
+ // some other thread could stop the operation and start a new one using same file descriptor, and
+ // we wouldn't know. To prevent this, the AppleService object's HaltOperation() routine is declared
+ // synchronized and we perform our checks synchronized on the AppleService object, which ensures
+ // that HaltOperation() can't execute while we're doing it. Because Java locks are re-entrant this
+ // locking DOESN'T prevent the callback routine from stopping its own operation, but DOES prevent
+ // any other thread from stopping it until after the callback has completed and returned to us here.
+
+ int result = BlockForData();
+ synchronized (this)