1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - util.h *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2012 Mupen64plus development team *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22 #include "workqueue.h"
23 #include "api/callbacks.h"
26 #include <SDL_thread.h>
28 #define WORKQUEUE_THREADS 1
30 struct workqueue_mgmt_globals {
31 struct list_head work_queue;
32 struct list_head thread_queue;
33 struct list_head thread_list;
37 struct workqueue_thread {
40 struct list_head list;
41 struct list_head list_mgmt;
44 static struct workqueue_mgmt_globals workqueue_mgmt;
46 static void workqueue_dismiss(struct work_struct *work)
50 static struct work_struct *workqueue_get_work(struct workqueue_thread *thread)
53 struct work_struct *work;
56 SDL_LockMutex(workqueue_mgmt.lock);
57 list_del_init(&thread->list);
58 if (!list_empty(&workqueue_mgmt.work_queue)) {
60 work = list_first_entry(&workqueue_mgmt.work_queue, struct work_struct, list);
61 list_del_init(&work->list);
63 list_add(&thread->list, &workqueue_mgmt.thread_queue);
64 SDL_CondWait(thread->work_avail, workqueue_mgmt.lock);
66 SDL_UnlockMutex(workqueue_mgmt.lock);
75 static int workqueue_thread_handler(void *data)
77 struct workqueue_thread *thread = data;
78 struct work_struct *work;
81 work = workqueue_get_work(thread);
82 if (work->func == workqueue_dismiss) {
93 int workqueue_init(void)
96 struct workqueue_thread *thread;
98 memset(&workqueue_mgmt, 0, sizeof(workqueue_mgmt));
99 INIT_LIST_HEAD(&workqueue_mgmt.work_queue);
100 INIT_LIST_HEAD(&workqueue_mgmt.thread_queue);
101 INIT_LIST_HEAD(&workqueue_mgmt.thread_list);
103 workqueue_mgmt.lock = SDL_CreateMutex();
104 if (!workqueue_mgmt.lock) {
105 DebugMessage(M64MSG_ERROR, "Could not create workqueue management");
109 SDL_LockMutex(workqueue_mgmt.lock);
110 for (i = 0; i < WORKQUEUE_THREADS; i++) {
111 thread = malloc(sizeof(*thread));
113 DebugMessage(M64MSG_ERROR, "Could not create workqueue thread management data");
114 SDL_UnlockMutex(workqueue_mgmt.lock);
118 memset(thread, 0, sizeof(*thread));
119 list_add(&thread->list_mgmt, &workqueue_mgmt.thread_list);
120 INIT_LIST_HEAD(&thread->list);
121 thread->work_avail = SDL_CreateCond();
122 if (!thread->work_avail) {
123 DebugMessage(M64MSG_ERROR, "Could not create workqueue thread work_avail condition");
124 SDL_UnlockMutex(workqueue_mgmt.lock);
128 #if SDL_VERSION_ATLEAST(2,0,0)
129 thread->thread = SDL_CreateThread(workqueue_thread_handler, "m64pwq", thread);
131 thread->thread = SDL_CreateThread(workqueue_thread_handler, thread);
133 if (!thread->thread) {
134 DebugMessage(M64MSG_ERROR, "Could not create workqueue thread handler");
135 SDL_UnlockMutex(workqueue_mgmt.lock);
139 SDL_UnlockMutex(workqueue_mgmt.lock);
144 void workqueue_shutdown(void)
148 struct work_struct *work;
149 struct workqueue_thread *thread, *safe;
151 for (i = 0; i < WORKQUEUE_THREADS; i++) {
152 work = malloc(sizeof(*work));
153 init_work(work, workqueue_dismiss);
157 list_for_each_entry_safe(thread, safe, &workqueue_mgmt.thread_list, struct workqueue_thread, list_mgmt) {
158 list_del(&thread->list_mgmt);
159 SDL_WaitThread(thread->thread, &status);
160 SDL_DestroyCond(thread->work_avail);
164 if (!list_empty(&workqueue_mgmt.work_queue))
165 DebugMessage(M64MSG_WARNING, "Stopped workqueue with work still pending");
167 SDL_DestroyMutex(workqueue_mgmt.lock);
170 int queue_work(struct work_struct *work)
172 struct workqueue_thread *thread;
174 SDL_LockMutex(workqueue_mgmt.lock);
175 list_add_tail(&work->list, &workqueue_mgmt.work_queue);
176 if (!list_empty(&workqueue_mgmt.thread_queue)) {
177 thread = list_first_entry(&workqueue_mgmt.thread_queue, struct workqueue_thread, list);
178 list_del_init(&thread->list);
180 SDL_CondSignal(thread->work_avail);
182 SDL_UnlockMutex(workqueue_mgmt.lock);