Home | History | Annotate | Download | only in nine
      1 /*
      2  * Copyright  2012 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #include "swapchain9.h"
     25 #include "surface9.h"
     26 #include "device9.h"
     27 
     28 #include "nine_helpers.h"
     29 #include "nine_pipe.h"
     30 #include "nine_dump.h"
     31 
     32 #include "util/u_inlines.h"
     33 #include "util/u_surface.h"
     34 #include "hud/hud_context.h"
     35 #include "state_tracker/drm_driver.h"
     36 
     37 #include "os/os_thread.h"
     38 #include "threadpool.h"
     39 
     40 static void *
     41 threadpool_worker(void *data)
     42 {
     43     struct threadpool *pool = data;
     44 
     45     pthread_mutex_lock(&pool->m);
     46 
     47     while (!pool->shutdown) {
     48         struct threadpool_task *task;
     49 
     50         /* Block (dropping the lock) until new work arrives for us. */
     51         while (!pool->workqueue && !pool->shutdown)
     52             pthread_cond_wait(&pool->new_work, &pool->m);
     53 
     54         if (pool->shutdown) {
     55             pthread_mutex_unlock(&pool->m);
     56             return NULL;
     57         }
     58 
     59         /* Pull the first task from the list.  We don't free it -- it now lacks
     60          * a reference other than the worker creator's, whose responsibility it
     61          * is to call threadpool_wait_for_work() to free it.
     62          */
     63         task = pool->workqueue;
     64         pool->workqueue = task->next;
     65 
     66         /* Call the task's work func. */
     67         pthread_mutex_unlock(&pool->m);
     68         task->work(task->data);
     69         pthread_mutex_lock(&pool->m);
     70         task->finished = TRUE;
     71         pthread_cond_broadcast(&task->finish);
     72     }
     73 
     74     pthread_mutex_unlock(&pool->m);
     75 
     76     return NULL;
     77 }
     78 
     79 struct threadpool *
     80 _mesa_threadpool_create(struct NineSwapChain9 *swapchain)
     81 {
     82     struct threadpool *pool = calloc(1, sizeof(*pool));
     83 
     84     if (!pool)
     85         return NULL;
     86 
     87     pthread_mutex_init(&pool->m, NULL);
     88     pthread_cond_init(&pool->new_work, NULL);
     89 
     90     pool->wthread = NineSwapChain9_CreateThread(swapchain, threadpool_worker, pool);
     91     if (!pool->wthread) {
     92         /* using pthread as fallback */
     93         pthread_create(&pool->pthread, NULL, threadpool_worker, pool);
     94     }
     95     return pool;
     96 }
     97 
     98 void
     99 _mesa_threadpool_destroy(struct NineSwapChain9 *swapchain, struct threadpool *pool)
    100 {
    101     if (!pool)
    102         return;
    103 
    104     pthread_mutex_lock(&pool->m);
    105     pool->shutdown = TRUE;
    106     pthread_cond_broadcast(&pool->new_work);
    107     pthread_mutex_unlock(&pool->m);
    108 
    109     if (pool->wthread) {
    110         NineSwapChain9_WaitForThread(swapchain, pool->wthread);
    111     } else {
    112         pthread_join(pool->pthread, NULL);
    113     }
    114 
    115     pthread_cond_destroy(&pool->new_work);
    116     pthread_mutex_destroy(&pool->m);
    117     free(pool);
    118 }
    119 
    120 /**
    121  * Queues a request for the work function to be asynchronously executed by the
    122  * thread pool.
    123  *
    124  * The work func will get the "data" argument as its parameter -- any
    125  * communication between the caller and the work function will occur through
    126  * that.
    127  *
    128  * If there is an error, the work function is called immediately and NULL is
    129  * returned.
    130  */
    131 struct threadpool_task *
    132 _mesa_threadpool_queue_task(struct threadpool *pool,
    133                             threadpool_task_func work, void *data)
    134 {
    135     struct threadpool_task *task, *previous;
    136 
    137     if (!pool) {
    138         work(data);
    139         return NULL;
    140     }
    141 
    142     task = calloc(1, sizeof(*task));
    143     if (!task) {
    144         work(data);
    145         return NULL;
    146     }
    147 
    148     task->work = work;
    149     task->data = data;
    150     task->next = NULL;
    151     pthread_cond_init(&task->finish, NULL);
    152 
    153     pthread_mutex_lock(&pool->m);
    154 
    155     if (!pool->workqueue) {
    156         pool->workqueue = task;
    157     } else {
    158         previous = pool->workqueue;
    159         while (previous && previous->next)
    160             previous = previous->next;
    161 
    162         previous->next = task;
    163     }
    164     pthread_cond_signal(&pool->new_work);
    165     pthread_mutex_unlock(&pool->m);
    166 
    167     return task;
    168 }
    169 
    170 /**
    171  * Blocks on the completion of the given task and frees the task.
    172  */
    173 void
    174 _mesa_threadpool_wait_for_task(struct threadpool *pool,
    175                                struct threadpool_task **task_handle)
    176 {
    177     struct threadpool_task *task = *task_handle;
    178 
    179     if (!pool || !task)
    180         return;
    181 
    182     pthread_mutex_lock(&pool->m);
    183     while (!task->finished)
    184         pthread_cond_wait(&task->finish, &pool->m);
    185     pthread_mutex_unlock(&pool->m);
    186 
    187     pthread_cond_destroy(&task->finish);
    188     free(task);
    189     *task_handle = NULL;
    190 }
    191