1c5971cd144c7b33e8bf2f38ebd296b3276014de7Jens Axboe/*
2c5971cd144c7b33e8bf2f38ebd296b3276014de7Jens Axboe * Basic workqueue like code, that sets up a thread and allows async
3c5971cd144c7b33e8bf2f38ebd296b3276014de7Jens Axboe * processing of some sort. Could be extended to allow for multiple
4c5971cd144c7b33e8bf2f38ebd296b3276014de7Jens Axboe * worker threads. But right now fio associates one of this per IO
5c5971cd144c7b33e8bf2f38ebd296b3276014de7Jens Axboe * thread, so should be enough to have just a single thread doing the
6c5971cd144c7b33e8bf2f38ebd296b3276014de7Jens Axboe * work.
7c5971cd144c7b33e8bf2f38ebd296b3276014de7Jens Axboe */
838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe#include <stdio.h>
938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe#include <stdlib.h>
1038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe#include <stdarg.h>
1138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe#include <unistd.h>
1238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe#include <errno.h>
1338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe#include <pthread.h>
14c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe#include <string.h>
1538a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
1665f93caca2ca0dd8d8150831f16854b3a8c3845aJens Axboe#include "../smalloc.h"
1765f93caca2ca0dd8d8150831f16854b3a8c3845aJens Axboe#include "../log.h"
1838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe#include "tp.h"
1938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
2038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboestatic void tp_flush_work(struct flist_head *list)
2138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe{
2238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	struct tp_work *work;
2338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
2438a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	while (!flist_empty(list)) {
25c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe		int prio;
26c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe
2738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		work = flist_entry(list->next, struct tp_work, list);
2838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		flist_del(&work->list);
29c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe
30c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe		prio = work->prio;
31c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe		if (nice(prio) < 0)
32c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe			log_err("fio: nice %s\n", strerror(errno));
33c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe
3438a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		work->fn(work);
35c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe
36c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe		if (nice(prio) < 0)
37c9a5f3981c3678d53e532296082ba80ded59f74aJens Axboe			log_err("fio: nice %s\n", strerror(errno));
3838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	}
3938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe}
4038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
4138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboestatic void *tp_thread(void *data)
4238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe{
4338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	struct tp_data *tdat = data;
4438a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	struct flist_head work_list;
4538a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
4638a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	INIT_FLIST_HEAD(&work_list);
4738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
4838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	while (1) {
4938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		pthread_mutex_lock(&tdat->lock);
5038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
5138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		if (!tdat->thread_exit && flist_empty(&tdat->work))
5238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe			pthread_cond_wait(&tdat->cv, &tdat->lock);
5338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
5412dbd06d3203840c8ebdc4d0a6135a69c4380949Jens Axboe		if (!flist_empty(&tdat->work))
5512dbd06d3203840c8ebdc4d0a6135a69c4380949Jens Axboe			flist_splice_tail_init(&tdat->work, &work_list);
5638a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
5738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		pthread_mutex_unlock(&tdat->lock);
5838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
5938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		if (flist_empty(&work_list)) {
6038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe			if (tdat->thread_exit)
6138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe				break;
6238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe			continue;
6338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		}
6438a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
6538a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		tp_flush_work(&work_list);
6638a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	}
6738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
6838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	return NULL;
6938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe}
7038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
7138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboevoid tp_queue_work(struct tp_data *tdat, struct tp_work *work)
7238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe{
7338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	work->done = 0;
7438a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
7538a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	pthread_mutex_lock(&tdat->lock);
7638a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	flist_add_tail(&work->list, &tdat->work);
7738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	pthread_mutex_unlock(&tdat->lock);
78de6504ecd252b953c5fecf7277b4a9cc002a6602Jens Axboe
79de6504ecd252b953c5fecf7277b4a9cc002a6602Jens Axboe	pthread_cond_signal(&tdat->cv);
8038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe}
8138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
8238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboevoid tp_init(struct tp_data **tdatp)
8338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe{
8438a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	struct tp_data *tdat;
8538a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	int ret;
8638a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
8738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	if (*tdatp)
8838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		return;
8938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
9038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	*tdatp = tdat = smalloc(sizeof(*tdat));
9138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	pthread_mutex_init(&tdat->lock, NULL);
9238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	INIT_FLIST_HEAD(&tdat->work);
9338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	pthread_cond_init(&tdat->cv, NULL);
9438a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	pthread_cond_init(&tdat->sleep_cv, NULL);
9538a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
9638a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	ret = pthread_create(&tdat->thread, NULL, tp_thread, tdat);
9738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	if (ret)
9838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		log_err("fio: failed to create tp thread\n");
9938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe}
10038a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
10138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboevoid tp_exit(struct tp_data **tdatp)
10238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe{
10338a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	struct tp_data *tdat = *tdatp;
10438a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	void *ret;
10538a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
10638a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	if (!tdat)
10738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe		return;
10838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
10938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	pthread_mutex_lock(&tdat->lock);
110de6504ecd252b953c5fecf7277b4a9cc002a6602Jens Axboe	tdat->thread_exit = 1;
11138a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	pthread_mutex_unlock(&tdat->lock);
11238a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
113de6504ecd252b953c5fecf7277b4a9cc002a6602Jens Axboe	pthread_cond_signal(&tdat->cv);
114de6504ecd252b953c5fecf7277b4a9cc002a6602Jens Axboe
11538a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	pthread_join(tdat->thread, &ret);
11638a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe
11738a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	sfree(tdat);
11838a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe	*tdatp = NULL;
11938a812d7fa79a673855efb6324c8fc68b92b89c1Jens Axboe}
120