+ EnterCriticalSection (&async_tp.lock);
+ threadpool_free_queue (&async_tp);
+ threadpool_kill_idle_threads (&async_tp);
+ LeaveCriticalSection (&async_tp.lock);
+ socket_io_cleanup (&socket_io_data); /* Empty when DISABLE_SOCKETS is defined */
+ /* Do we want/need these?
+ DeleteCriticalSection (&async_tp.lock);
+ DeleteCriticalSection (&async_tp.table_lock);
+ DeleteCriticalSection (&socket_io_data.io_lock);
+ */
+}
+
+static void
+null_array (MonoArray *a, int first, int last)
+{
+ /* We must null the old array because it might
+ contain cross-appdomain references, which
+ will crash the GC when the domains are
+ unloaded. */
+ memset (mono_array_addr (a, MonoObject*, first), 0, sizeof (MonoObject*) * (last - first));
+}
+
+/* Caller must enter &tp->lock */
+static MonoObject*
+dequeue_job_nolock (ThreadPool *tp)
+{
+ MonoObject *ar;
+ int count;
+
+ if (!tp->array || tp->first_elem == tp->next_elem)
+ return NULL;
+ ar = mono_array_get (tp->array, MonoObject*, tp->first_elem);
+ mono_array_set (tp->array, MonoObject*, tp->first_elem, NULL);
+ tp->first_elem++;
+ count = tp->next_elem - tp->first_elem;
+ /* reduce the size of the array if it's mostly empty */
+ if (mono_array_length (tp->array) > INITIAL_QUEUE_LENGTH && count < (mono_array_length (tp->array) / 3)) {
+ MonoArray *newa = mono_array_new_cached (mono_get_root_domain (), mono_defaults.object_class, mono_array_length (tp->array) / 2);
+ mono_array_memcpy_refs (newa, 0, tp->array, tp->first_elem, count);
+ null_array (tp->array, tp->first_elem, tp->next_elem);
+ tp->array = newa;
+ tp->first_elem = 0;
+ tp->next_elem = count;
+ }
+ return ar;
+}
+
+/* Call after entering &tp->lock */
+static int
+signal_idle_threads (ThreadPool *tp)
+{
+ IdleThreadData *it;
+ int result = 0;
+ int njobs;
+
+ njobs = tp->next_elem - tp->first_elem;
+ while (njobs > 0 && (it = g_queue_pop_head (tp->idle_threads)) != NULL) {
+ it->data = dequeue_job_nolock (tp);
+ if (it->data == NULL)
+ break; /* Should never happen */
+ result++;
+ njobs--;
+ it->timeout = INFINITE;
+ SetEvent (it->wait_handle);
+ }
+ return njobs;
+}
+
+/* Call after entering &tp->lock */
+static gboolean
+threadpool_start_thread (ThreadPool *tp, gpointer arg)
+{
+ gint max;
+ gint n;
+
+ max = (gint) InterlockedCompareExchange (&tp->max_threads, 0, -1);
+ n = (gint) InterlockedCompareExchange (&tp->nthreads, 0, -1);
+ if (max <= n)
+ return FALSE;
+ InterlockedIncrement (&tp->nthreads);
+ mono_thread_create_internal (mono_get_root_domain (), tp->async_invoke, arg, TRUE);
+ return TRUE;
+}