osd_work_queue *osd_work_queue_alloc(int flags) { int threadnum; int numprocs = effective_num_processors(); osd_work_queue *queue; int osdthreadnum = 0; int allocthreadnum; char *osdworkqueuemaxthreads = osd_getenv(ENV_WORKQUEUEMAXTHREADS); // allocate a new queue queue = (osd_work_queue *)osd_malloc(sizeof(*queue)); if (queue == NULL) goto error; memset(queue, 0, sizeof(*queue)); // initialize basic queue members queue->tailptr = (osd_work_item **)&queue->list; queue->flags = flags; // allocate events for the queue queue->doneevent = osd_event_alloc(TRUE, TRUE); // manual reset, signalled if (queue->doneevent == NULL) goto error; // initialize the critical section queue->lock = osd_scalable_lock_alloc(); if (queue->lock == NULL) goto error; // determine how many threads to create... // on a single-CPU system, create 1 thread for I/O queues, and 0 threads for everything else if (numprocs == 1) threadnum = (flags & WORK_QUEUE_FLAG_IO) ? 1 : 0; // on an n-CPU system, create n-1 threads for multi queues, and 1 thread for everything else else threadnum = (flags & WORK_QUEUE_FLAG_MULTI) ? (numprocs - 1) : 1; if (osdworkqueuemaxthreads != NULL && sscanf(osdworkqueuemaxthreads, "%d", &osdthreadnum) == 1 && threadnum > osdthreadnum) threadnum = osdthreadnum; // clamp to the maximum queue->threads = MIN(threadnum, WORK_MAX_THREADS); // allocate memory for thread array (+1 to count the calling thread if WORK_QUEUE_FLAG_MULTI) if (flags & WORK_QUEUE_FLAG_MULTI) allocthreadnum = queue->threads + 1; else allocthreadnum = queue->threads; #if KEEP_STATISTICS printf("osdprocs: %d effecprocs: %d threads: %d allocthreads: %d osdthreads: %d maxthreads: %d queuethreads: %d\n", osd_num_processors, numprocs, threadnum, allocthreadnum, osdthreadnum, WORK_MAX_THREADS, queue->threads); #endif queue->thread = (work_thread_info *)osd_malloc_array(allocthreadnum * sizeof(queue->thread[0])); if (queue->thread == NULL) goto error; memset(queue->thread, 0, allocthreadnum * sizeof(queue->thread[0])); // iterate over threads for (threadnum = 0; threadnum < queue->threads; threadnum++) { work_thread_info *thread = &queue->thread[threadnum]; // set a pointer back to the queue thread->queue = queue; // create the per-thread wake event thread->wakeevent = osd_event_alloc(FALSE, FALSE); // auto-reset, not signalled if (thread->wakeevent == NULL) goto error; // create the thread thread->handle = osd_thread_create(worker_thread_entry, thread); if (thread->handle == NULL) goto error; // set its priority: I/O threads get high priority because they are assumed to be // blocked most of the time; other threads just match the creator's priority if (flags & WORK_QUEUE_FLAG_IO) osd_thread_adjust_priority(thread->handle, 1); else osd_thread_adjust_priority(thread->handle, 0); } // start a timer going for "waittime" on the main thread if (flags & WORK_QUEUE_FLAG_MULTI) { begin_timing(queue->thread[queue->threads].waittime); } return queue; error: osd_work_queue_free(queue); return NULL; }
osd_work_queue *osd_work_queue_alloc(int flags) { int numprocs = effective_num_processors(); osd_work_queue *queue; int threadnum; // allocate a new queue queue = (osd_work_queue *)osd_malloc(sizeof(*queue)); if (queue == NULL) goto error; memset(queue, 0, sizeof(*queue)); // initialize basic queue members queue->tailptr = (osd_work_item **)&queue->list; queue->flags = flags; // allocate events for the queue queue->doneevent = osd_event_alloc(TRUE, TRUE); // manual reset, signalled if (queue->doneevent == NULL) goto error; // initialize the critical section queue->lock = osd_scalable_lock_alloc(); if (queue->lock == NULL) goto error; // determine how many threads to create... // on a single-CPU system, create 1 thread for I/O queues, and 0 threads for everything else if (numprocs == 1) queue->threads = (flags & WORK_QUEUE_FLAG_IO) ? 1 : 0; // on an n-CPU system, create (n-1) threads for multi queues, and 1 thread for everything else else queue->threads = (flags & WORK_QUEUE_FLAG_MULTI) ? (numprocs - 1) : 1; // clamp to the maximum queue->threads = MIN(queue->threads, WORK_MAX_THREADS); // allocate memory for thread array (+1 to count the calling thread) queue->thread = (work_thread_info *)osd_malloc_array((queue->threads + 1) * sizeof(queue->thread[0])); if (queue->thread == NULL) goto error; memset(queue->thread, 0, (queue->threads + 1) * sizeof(queue->thread[0])); // iterate over threads for (threadnum = 0; threadnum < queue->threads; threadnum++) { work_thread_info *thread = &queue->thread[threadnum]; // set a pointer back to the queue thread->queue = queue; // create the per-thread wake event thread->wakeevent = osd_event_alloc(FALSE, FALSE); // auto-reset, not signalled if (thread->wakeevent == NULL) goto error; // create the thread thread->handle = osd_thread_create(worker_thread_entry, thread); if (thread->handle == NULL) goto error; // set its priority: I/O threads get high priority because they are assumed to be // blocked most of the time; other threads just match the creator's priority if (flags & WORK_QUEUE_FLAG_IO) osd_thread_adjust_priority(thread->handle, 1); else osd_thread_adjust_priority(thread->handle, 0); // Bind main thread to cpu 0 osd_thread_cpu_affinity(NULL, effective_cpu_mask(0)); if (flags & WORK_QUEUE_FLAG_IO) osd_thread_cpu_affinity(thread->handle, effective_cpu_mask(1)); else osd_thread_cpu_affinity(thread->handle, effective_cpu_mask(2+threadnum) ); } // start a timer going for "waittime" on the main thread begin_timing(queue->thread[queue->threads].waittime); return queue; error: osd_work_queue_free(queue); return NULL; }