| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <pthread.h> |
| |
| #include "smalloc.h" |
| #include "log.h" |
| #include "tp.h" |
| |
| static void tp_flush_work(struct flist_head *list) |
| { |
| struct tp_work *work; |
| |
| while (!flist_empty(list)) { |
| work = flist_entry(list->next, struct tp_work, list); |
| flist_del(&work->list); |
| work->fn(work); |
| } |
| } |
| |
| static void *tp_thread(void *data) |
| { |
| struct tp_data *tdat = data; |
| struct flist_head work_list; |
| |
| INIT_FLIST_HEAD(&work_list); |
| |
| while (1) { |
| pthread_mutex_lock(&tdat->lock); |
| |
| if (!tdat->thread_exit && flist_empty(&tdat->work)) |
| pthread_cond_wait(&tdat->cv, &tdat->lock); |
| |
| if (!flist_empty(&tdat->work)) { |
| flist_splice(&tdat->work, &work_list); |
| INIT_FLIST_HEAD(&tdat->work); |
| } |
| |
| pthread_mutex_unlock(&tdat->lock); |
| |
| if (flist_empty(&work_list)) { |
| if (tdat->thread_exit) |
| break; |
| continue; |
| } |
| |
| tp_flush_work(&work_list); |
| } |
| |
| return NULL; |
| } |
| |
| void tp_queue_work(struct tp_data *tdat, struct tp_work *work) |
| { |
| work->done = 0; |
| |
| pthread_mutex_lock(&tdat->lock); |
| flist_add_tail(&work->list, &tdat->work); |
| pthread_cond_signal(&tdat->cv); |
| pthread_mutex_unlock(&tdat->lock); |
| } |
| |
| void tp_init(struct tp_data **tdatp) |
| { |
| struct tp_data *tdat; |
| int ret; |
| |
| if (*tdatp) |
| return; |
| |
| *tdatp = tdat = smalloc(sizeof(*tdat)); |
| pthread_mutex_init(&tdat->lock, NULL); |
| INIT_FLIST_HEAD(&tdat->work); |
| pthread_cond_init(&tdat->cv, NULL); |
| pthread_cond_init(&tdat->sleep_cv, NULL); |
| |
| ret = pthread_create(&tdat->thread, NULL, tp_thread, tdat); |
| if (ret) |
| log_err("fio: failed to create tp thread\n"); |
| } |
| |
| void tp_exit(struct tp_data **tdatp) |
| { |
| struct tp_data *tdat = *tdatp; |
| void *ret; |
| |
| if (!tdat) |
| return; |
| |
| tdat->thread_exit = 1; |
| pthread_mutex_lock(&tdat->lock); |
| pthread_cond_signal(&tdat->cv); |
| pthread_mutex_unlock(&tdat->lock); |
| |
| pthread_join(tdat->thread, &ret); |
| |
| sfree(tdat); |
| *tdatp = NULL; |
| } |