1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker #include <pthread.h>
3*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
4*33b1fccfSAndroid Build Coastguard Worker #include "erofs/workqueue.h"
5*33b1fccfSAndroid Build Coastguard Worker
worker_thread(void * arg)6*33b1fccfSAndroid Build Coastguard Worker static void *worker_thread(void *arg)
7*33b1fccfSAndroid Build Coastguard Worker {
8*33b1fccfSAndroid Build Coastguard Worker struct erofs_workqueue *wq = arg;
9*33b1fccfSAndroid Build Coastguard Worker struct erofs_work *work;
10*33b1fccfSAndroid Build Coastguard Worker void *tlsp = NULL;
11*33b1fccfSAndroid Build Coastguard Worker
12*33b1fccfSAndroid Build Coastguard Worker if (wq->on_start)
13*33b1fccfSAndroid Build Coastguard Worker tlsp = (wq->on_start)(wq, NULL);
14*33b1fccfSAndroid Build Coastguard Worker
15*33b1fccfSAndroid Build Coastguard Worker while (true) {
16*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_lock(&wq->lock);
17*33b1fccfSAndroid Build Coastguard Worker
18*33b1fccfSAndroid Build Coastguard Worker while (wq->job_count == 0 && !wq->shutdown)
19*33b1fccfSAndroid Build Coastguard Worker pthread_cond_wait(&wq->cond_empty, &wq->lock);
20*33b1fccfSAndroid Build Coastguard Worker if (wq->job_count == 0 && wq->shutdown) {
21*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&wq->lock);
22*33b1fccfSAndroid Build Coastguard Worker break;
23*33b1fccfSAndroid Build Coastguard Worker }
24*33b1fccfSAndroid Build Coastguard Worker
25*33b1fccfSAndroid Build Coastguard Worker work = wq->head;
26*33b1fccfSAndroid Build Coastguard Worker wq->head = work->next;
27*33b1fccfSAndroid Build Coastguard Worker if (!wq->head)
28*33b1fccfSAndroid Build Coastguard Worker wq->tail = NULL;
29*33b1fccfSAndroid Build Coastguard Worker wq->job_count--;
30*33b1fccfSAndroid Build Coastguard Worker
31*33b1fccfSAndroid Build Coastguard Worker if (wq->job_count == wq->max_jobs - 1)
32*33b1fccfSAndroid Build Coastguard Worker pthread_cond_broadcast(&wq->cond_full);
33*33b1fccfSAndroid Build Coastguard Worker
34*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&wq->lock);
35*33b1fccfSAndroid Build Coastguard Worker work->fn(work, tlsp);
36*33b1fccfSAndroid Build Coastguard Worker }
37*33b1fccfSAndroid Build Coastguard Worker
38*33b1fccfSAndroid Build Coastguard Worker if (wq->on_exit)
39*33b1fccfSAndroid Build Coastguard Worker (void)(wq->on_exit)(wq, tlsp);
40*33b1fccfSAndroid Build Coastguard Worker return NULL;
41*33b1fccfSAndroid Build Coastguard Worker }
42*33b1fccfSAndroid Build Coastguard Worker
erofs_alloc_workqueue(struct erofs_workqueue * wq,unsigned int nworker,unsigned int max_jobs,erofs_wq_func_t on_start,erofs_wq_func_t on_exit)43*33b1fccfSAndroid Build Coastguard Worker int erofs_alloc_workqueue(struct erofs_workqueue *wq, unsigned int nworker,
44*33b1fccfSAndroid Build Coastguard Worker unsigned int max_jobs, erofs_wq_func_t on_start,
45*33b1fccfSAndroid Build Coastguard Worker erofs_wq_func_t on_exit)
46*33b1fccfSAndroid Build Coastguard Worker {
47*33b1fccfSAndroid Build Coastguard Worker unsigned int i;
48*33b1fccfSAndroid Build Coastguard Worker int ret;
49*33b1fccfSAndroid Build Coastguard Worker
50*33b1fccfSAndroid Build Coastguard Worker if (!wq || nworker <= 0 || max_jobs <= 0)
51*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
52*33b1fccfSAndroid Build Coastguard Worker
53*33b1fccfSAndroid Build Coastguard Worker wq->head = wq->tail = NULL;
54*33b1fccfSAndroid Build Coastguard Worker wq->nworker = nworker;
55*33b1fccfSAndroid Build Coastguard Worker wq->max_jobs = max_jobs;
56*33b1fccfSAndroid Build Coastguard Worker wq->job_count = 0;
57*33b1fccfSAndroid Build Coastguard Worker wq->shutdown = false;
58*33b1fccfSAndroid Build Coastguard Worker wq->on_start = on_start;
59*33b1fccfSAndroid Build Coastguard Worker wq->on_exit = on_exit;
60*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_init(&wq->lock, NULL);
61*33b1fccfSAndroid Build Coastguard Worker pthread_cond_init(&wq->cond_empty, NULL);
62*33b1fccfSAndroid Build Coastguard Worker pthread_cond_init(&wq->cond_full, NULL);
63*33b1fccfSAndroid Build Coastguard Worker
64*33b1fccfSAndroid Build Coastguard Worker wq->workers = malloc(nworker * sizeof(pthread_t));
65*33b1fccfSAndroid Build Coastguard Worker if (!wq->workers)
66*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
67*33b1fccfSAndroid Build Coastguard Worker
68*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < nworker; i++) {
69*33b1fccfSAndroid Build Coastguard Worker ret = pthread_create(&wq->workers[i], NULL, worker_thread, wq);
70*33b1fccfSAndroid Build Coastguard Worker if (ret) {
71*33b1fccfSAndroid Build Coastguard Worker while (i)
72*33b1fccfSAndroid Build Coastguard Worker pthread_cancel(wq->workers[--i]);
73*33b1fccfSAndroid Build Coastguard Worker free(wq->workers);
74*33b1fccfSAndroid Build Coastguard Worker return ret;
75*33b1fccfSAndroid Build Coastguard Worker }
76*33b1fccfSAndroid Build Coastguard Worker }
77*33b1fccfSAndroid Build Coastguard Worker return 0;
78*33b1fccfSAndroid Build Coastguard Worker }
79*33b1fccfSAndroid Build Coastguard Worker
erofs_queue_work(struct erofs_workqueue * wq,struct erofs_work * work)80*33b1fccfSAndroid Build Coastguard Worker int erofs_queue_work(struct erofs_workqueue *wq, struct erofs_work *work)
81*33b1fccfSAndroid Build Coastguard Worker {
82*33b1fccfSAndroid Build Coastguard Worker if (!wq || !work)
83*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
84*33b1fccfSAndroid Build Coastguard Worker
85*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_lock(&wq->lock);
86*33b1fccfSAndroid Build Coastguard Worker
87*33b1fccfSAndroid Build Coastguard Worker while (wq->job_count == wq->max_jobs)
88*33b1fccfSAndroid Build Coastguard Worker pthread_cond_wait(&wq->cond_full, &wq->lock);
89*33b1fccfSAndroid Build Coastguard Worker
90*33b1fccfSAndroid Build Coastguard Worker work->next = NULL;
91*33b1fccfSAndroid Build Coastguard Worker if (!wq->head)
92*33b1fccfSAndroid Build Coastguard Worker wq->head = work;
93*33b1fccfSAndroid Build Coastguard Worker else
94*33b1fccfSAndroid Build Coastguard Worker wq->tail->next = work;
95*33b1fccfSAndroid Build Coastguard Worker wq->tail = work;
96*33b1fccfSAndroid Build Coastguard Worker wq->job_count++;
97*33b1fccfSAndroid Build Coastguard Worker
98*33b1fccfSAndroid Build Coastguard Worker pthread_cond_signal(&wq->cond_empty);
99*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&wq->lock);
100*33b1fccfSAndroid Build Coastguard Worker return 0;
101*33b1fccfSAndroid Build Coastguard Worker }
102*33b1fccfSAndroid Build Coastguard Worker
erofs_destroy_workqueue(struct erofs_workqueue * wq)103*33b1fccfSAndroid Build Coastguard Worker int erofs_destroy_workqueue(struct erofs_workqueue *wq)
104*33b1fccfSAndroid Build Coastguard Worker {
105*33b1fccfSAndroid Build Coastguard Worker unsigned int i;
106*33b1fccfSAndroid Build Coastguard Worker
107*33b1fccfSAndroid Build Coastguard Worker if (!wq)
108*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
109*33b1fccfSAndroid Build Coastguard Worker
110*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_lock(&wq->lock);
111*33b1fccfSAndroid Build Coastguard Worker wq->shutdown = true;
112*33b1fccfSAndroid Build Coastguard Worker pthread_cond_broadcast(&wq->cond_empty);
113*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&wq->lock);
114*33b1fccfSAndroid Build Coastguard Worker
115*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < wq->nworker; i++)
116*33b1fccfSAndroid Build Coastguard Worker pthread_join(wq->workers[i], NULL);
117*33b1fccfSAndroid Build Coastguard Worker
118*33b1fccfSAndroid Build Coastguard Worker free(wq->workers);
119*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_destroy(&wq->lock);
120*33b1fccfSAndroid Build Coastguard Worker pthread_cond_destroy(&wq->cond_empty);
121*33b1fccfSAndroid Build Coastguard Worker pthread_cond_destroy(&wq->cond_full);
122*33b1fccfSAndroid Build Coastguard Worker return 0;
123*33b1fccfSAndroid Build Coastguard Worker }
124