private void RequestProcessorLoop()
{
// _ready: indicates that there are requests in the queue that should be processed.
// _stop: indicates that the class is being disposed and the thread should terminate.
WaitHandle[] wait = { _ready, _stop };
// Wait until a request is ready or the thread is being stopped. The WaitAny will return 0 (the index of
// _ready in the wait array) if a request is ready, and 1 when _stop is signaled, breaking us out of the loop.
while (WaitHandle.WaitAny(wait) == 0)
{
HttpListenerContext context;
bool isRecursiveRequestContext; // needs to be declared outside the lock but initialized afte we have the context.
lock (_queue)
{
if (_queue.Count > 0)
{
context = _queue.Dequeue();
}
else
{
_ready.Reset();
continue;
}
isRecursiveRequestContext = IsRecursiveRequestContext(context);
if (isRecursiveRequestContext)
{
_threadsDoingRecursiveRequests++;
// We've got to have some threads not doing recursive tasks.
// One non-recursive thread is probably enough to prevent deadlock but some of those
// threads are probably reading files so having a few of them
// is likely to speed up the recursive task.
if (_threadsDoingRecursiveRequests > _workers.Count - 3)
SpinUpAWorker();
}
}
var rawurl = "unknown";
try
{
rawurl = context.Request.RawUrl;
// set lower priority for thumbnails in order to have less impact on the UI thread
if (rawurl.Contains("thumbnail=1"))
Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
MakeReply(new RequestInfo(context));
}
catch (HttpListenerException e)
{
// http://stackoverflow.com/questions/4801868/c-sharp-problem-with-httplistener
Logger.WriteEvent("At ServerBase: ListenerCallback(): HttpListenerException, which may indicate that the caller closed the connection before we could reply. msg=" + e.Message);
Logger.WriteEvent("At ServerBase: ListenerCallback(): url=" + rawurl);
}
catch (Exception error)
{
#if __MonoCS__
// Something keeps closing the socket connection prematurely on Linux/Mono. But I'm not sure
// it's an important failure since the program appears to work okay, so we'll ignore the error.
if (error is IOException && error.InnerException != null && error.InnerException is System.Net.Sockets.SocketException)
{
Logger.WriteEvent("At ServerBase: ListenerCallback(): IOException/SocketException, which may indicate that the caller closed the connection before we could reply. msg=" + error.Message + " / " + error.InnerException.Message);
Logger.WriteEvent("At ServerBase: ListenerCallback(): url=" + rawurl);
}
else
#endif
{
Logger.WriteEvent("At ServerBase: ListenerCallback(): msg=" + error.Message);
Logger.WriteEvent("At ServerBase: ListenerCallback(): url=" + rawurl);
Logger.WriteEvent("At ServerBase: ListenerCallback(): stack=");
Logger.WriteEvent(error.StackTrace);
#if DEBUG
//NB: "throw" here makes it impossible for even the programmer to continue and try to see how it happens
Debug.Fail("(Debug Only) "+error.Message);
#endif
}
}
finally
{
Thread.CurrentThread.Priority = ThreadPriority.Normal;
if (isRecursiveRequestContext)
{
lock (_queue)
{
_threadsDoingRecursiveRequests--;
}
}
}
}
}