11 struct list_head node
;
14 void (*job_cb
)(void *data
);
15 void (*free_cb
)(void *data
);
19 static LIST_HEAD(worker_job_head
);
20 static pthread_mutex_t worker_mutex
= CMUS_MUTEX_INITIALIZER
;
21 static pthread_cond_t worker_cond
= PTHREAD_COND_INITIALIZER
;
22 static pthread_t worker_thread
;
23 static int running
= 1;
24 static int cancel_type
= JOB_TYPE_NONE
;
27 * - only worker thread modifies this
28 * - cur_job->job_cb can read this without locking
29 * - anyone else must lock worker before reading this
31 static struct worker_job
*cur_job
= NULL
;
33 #define worker_lock() cmus_mutex_lock(&worker_mutex)
34 #define worker_unlock() cmus_mutex_unlock(&worker_mutex)
36 static void *worker_loop(void *arg
)
40 if (list_empty(&worker_job_head
)) {
46 rc
= pthread_cond_wait(&worker_cond
, &worker_mutex
);
48 d_print("pthread_cond_wait: %s\n", strerror(rc
));
50 struct list_head
*item
= worker_job_head
.next
;
54 cur_job
= container_of(item
, struct worker_job
, node
);
58 cur_job
->job_cb(cur_job
->data
);
60 timer_print("worker job", et
- st
);
63 cur_job
->free_cb(cur_job
->data
);
67 // wakeup worker_remove_jobs() if needed
68 if (cancel_type
!= JOB_TYPE_NONE
)
69 pthread_cond_signal(&worker_cond
);
76 void worker_init(void)
78 int rc
= pthread_create(&worker_thread
, NULL
, worker_loop
, NULL
);
83 void worker_exit(void)
87 pthread_cond_signal(&worker_cond
);
90 pthread_join(worker_thread
, NULL
);
93 void worker_add_job(int type
, void (*job_cb
)(void *data
),
94 void (*free_cb
)(void *data
), void *data
)
96 struct worker_job
*job
;
98 job
= xnew(struct worker_job
, 1);
100 job
->job_cb
= job_cb
;
101 job
->free_cb
= free_cb
;
105 list_add_tail(&job
->node
, &worker_job_head
);
106 pthread_cond_signal(&worker_cond
);
110 void worker_remove_jobs(int type
)
112 struct list_head
*item
;
117 /* remove jobs of the specified type from the queue */
118 item
= worker_job_head
.next
;
119 while (item
!= &worker_job_head
) {
120 struct worker_job
*job
= container_of(item
, struct worker_job
, node
);
121 struct list_head
*next
= item
->next
;
123 if (type
== JOB_TYPE_ANY
|| type
== job
->type
) {
124 list_del(&job
->node
);
125 job
->free_cb(job
->data
);
131 /* wait current job to finish or cancel if it's of the specified type */
132 if (cur_job
&& (type
== JOB_TYPE_ANY
|| type
== cur_job
->type
))
133 pthread_cond_wait(&worker_cond
, &worker_mutex
);
135 cancel_type
= JOB_TYPE_NONE
;
139 int worker_has_job(int type
)
141 struct worker_job
*job
;
145 list_for_each_entry(job
, &worker_job_head
, node
) {
146 if (type
== JOB_TYPE_ANY
|| type
== job
->type
) {
151 if (cur_job
&& (type
== JOB_TYPE_ANY
|| type
== cur_job
->type
))
158 * this is only called from the worker thread
159 * cur_job is guaranteed to be non-NULL
161 int worker_cancelling(void)
163 return cur_job
->type
== cancel_type
|| cancel_type
== JOB_TYPE_ANY
;