xref: /aosp_15_r20/external/erofs-utils/lib/workqueue.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
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