diff --git a/common_thread.h b/common_thread.h index 277f7435cc..8317d07941 100644 --- a/common_thread.h +++ b/common_thread.h @@ -119,6 +119,14 @@ typedef struct blas_queue { struct blas_queue *next; #if defined( __WIN32__) || defined(__CYGWIN32__) || defined(_WIN32) || defined(__CYGWIN__) + /* + * Link used exclusively by the Windows thread pool to chain the jobs that + * are waiting to be picked up. It is deliberately kept separate from + * "next" above, which is owned (and rebuilt on every call) by whoever + * submitted the job: appending to the pool must never write into the + * queue nodes of another caller. + */ + struct blas_queue *pool_next; CRITICAL_SECTION lock; HANDLE finish; volatile int finished; diff --git a/driver/others/blas_server_win32.c b/driver/others/blas_server_win32.c index 0fc78eafa6..3fd167861a 100644 --- a/driver/others/blas_server_win32.c +++ b/driver/others/blas_server_win32.c @@ -57,6 +57,7 @@ typedef struct{ HANDLE killed; blas_queue_t *queue; /* Parameter Pointer */ + blas_queue_t *tail; /* Last job waiting in "queue", for O(1) append */ int shutdown; /* server shutdown flag */ } blas_pool_t; @@ -242,7 +243,10 @@ static DWORD WINAPI blas_thread_server(void *arg){ EnterCriticalSection(&pool.lock); queue = pool.queue; - if (queue) pool.queue = queue->next; + if (queue) { + pool.queue = queue->pool_next; + if (pool.queue == NULL) pool.tail = NULL; + } LeaveCriticalSection(&pool.lock); @@ -380,6 +384,7 @@ int blas_thread_init(void){ pool.shutdown = 0; pool.queue = NULL; + pool.tail = NULL; for(i = 0; i < blas_cpu_number - 1; i++){ blas_threads[i] = CreateThread(NULL, 0, @@ -411,7 +416,7 @@ int exec_blas_async(BLASLONG pos, blas_queue_t *queue){ if (unlikely(blas_server_avail == 0)) blas_thread_init(); #endif - blas_queue_t *current; + blas_queue_t *current, *last = NULL; current = queue; @@ -425,19 +430,22 @@ int exec_blas_async(BLASLONG pos, blas_queue_t *queue){ __asm__ __volatile__ ("stmxcsr %0" : "=m" (current -> sse_mode)); #endif + /* Build the pool's own chain over this caller's jobs */ + current -> pool_next = current -> next; + last = current; + current = current -> next; pos ++; } EnterCriticalSection(&pool.lock); - if (pool.queue) { - current = pool.queue; - while (current -> next) current = current -> next; - current -> next = queue; + if (pool.tail) { + pool.tail -> pool_next = queue; } else { pool.queue = queue; } + pool.tail = last; LeaveCriticalSection(&pool.lock); @@ -574,6 +582,7 @@ void goto_set_num_threads(int num_threads) pool.shutdown = 0; pool.queue = NULL; + pool.tail = NULL; blas_server_avail = 1; }