mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	FreeBSD: Improve taskq wrapper
- Group tqent_task and tqent_timeout_task into a union. They are never used same time. This shrinks taskq_ent_t from 192 to 160 bytes. - Remove tqent_registered. Use tqent_id != 0 instead. - Remove tqent_cancelled. Use taskqueue pending counter instead. - Change tqent_type into uint_t. We don't need to pack it any more. - Change tqent_rc into uint_t, matching refcount(9). - Take shared locks in taskq_lookup(). - Call proper taskqueue_drain_timeout() for TIMEOUT_TASK in taskq_cancel_id() and taskq_wait_id(). - Switch from CK_LIST to regular LIST. Reviewed-by: Allan Jude <allan@klarasystems.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Mateusz Guzik <mjguzik@gmail.com> Signed-off-by: Alexander Motin <mav@FreeBSD.org> Sponsored by: iXsystems, Inc. Closes #15356
This commit is contained in:
		
							parent
							
								
									459c99ff23
								
							
						
					
					
						commit
						b76724ae47
					
				| @ -30,9 +30,9 @@ | |||||||
| 
 | 
 | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/proc.h> | #include <sys/proc.h> | ||||||
|  | #include <sys/queue.h> | ||||||
| #include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||||
| #include <sys/thread.h> | #include <sys/thread.h> | ||||||
| #include <sys/ck.h> |  | ||||||
| 
 | 
 | ||||||
| #ifdef	__cplusplus | #ifdef	__cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -48,16 +48,16 @@ typedef uintptr_t taskqid_t; | |||||||
| typedef void (task_func_t)(void *); | typedef void (task_func_t)(void *); | ||||||
| 
 | 
 | ||||||
| typedef struct taskq_ent { | typedef struct taskq_ent { | ||||||
|  | 	union { | ||||||
| 		struct task	 tqent_task; | 		struct task	 tqent_task; | ||||||
| 		struct timeout_task tqent_timeout_task; | 		struct timeout_task tqent_timeout_task; | ||||||
|  | 	}; | ||||||
| 	task_func_t	*tqent_func; | 	task_func_t	*tqent_func; | ||||||
| 	void		*tqent_arg; | 	void		*tqent_arg; | ||||||
| 	taskqid_t	 tqent_id; | 	taskqid_t	 tqent_id; | ||||||
| 	CK_LIST_ENTRY(taskq_ent) tqent_hash; | 	LIST_ENTRY(taskq_ent) tqent_hash; | ||||||
| 	uint8_t tqent_type; | 	uint_t		 tqent_type; | ||||||
| 	uint8_t tqent_registered; | 	volatile uint_t	 tqent_rc; | ||||||
| 	uint8_t tqent_cancelled; |  | ||||||
| 	volatile uint32_t tqent_rc; |  | ||||||
| } taskq_ent_t; | } taskq_ent_t; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | |||||||
| @ -30,8 +30,6 @@ | |||||||
| __FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||||
| 
 | 
 | ||||||
| #include <sys/param.h> | #include <sys/param.h> | ||||||
| #include <sys/ck.h> |  | ||||||
| #include <sys/epoch.h> |  | ||||||
| #include <sys/kernel.h> | #include <sys/kernel.h> | ||||||
| #include <sys/kmem.h> | #include <sys/kmem.h> | ||||||
| #include <sys/lock.h> | #include <sys/lock.h> | ||||||
| @ -70,7 +68,7 @@ extern int uma_align_cache; | |||||||
| 
 | 
 | ||||||
| static MALLOC_DEFINE(M_TASKQ, "taskq", "taskq structures"); | static MALLOC_DEFINE(M_TASKQ, "taskq", "taskq structures"); | ||||||
| 
 | 
 | ||||||
| static CK_LIST_HEAD(tqenthashhead, taskq_ent) *tqenthashtbl; | static LIST_HEAD(tqenthashhead, taskq_ent) *tqenthashtbl; | ||||||
| static unsigned long tqenthash; | static unsigned long tqenthash; | ||||||
| static unsigned long tqenthashlock; | static unsigned long tqenthashlock; | ||||||
| static struct sx *tqenthashtbl_lock; | static struct sx *tqenthashtbl_lock; | ||||||
| @ -80,8 +78,8 @@ static taskqid_t tqidnext; | |||||||
| #define	TQIDHASH(tqid) (&tqenthashtbl[(tqid) & tqenthash]) | #define	TQIDHASH(tqid) (&tqenthashtbl[(tqid) & tqenthash]) | ||||||
| #define	TQIDHASHLOCK(tqid) (&tqenthashtbl_lock[((tqid) & tqenthashlock)]) | #define	TQIDHASHLOCK(tqid) (&tqenthashtbl_lock[((tqid) & tqenthashlock)]) | ||||||
| 
 | 
 | ||||||
|  | #define	NORMAL_TASK 0 | ||||||
| #define	TIMEOUT_TASK 1 | #define	TIMEOUT_TASK 1 | ||||||
| #define	NORMAL_TASK 2 |  | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| system_taskq_init(void *arg) | system_taskq_init(void *arg) | ||||||
| @ -121,7 +119,7 @@ system_taskq_fini(void *arg) | |||||||
| 	for (i = 0; i < tqenthashlock + 1; i++) | 	for (i = 0; i < tqenthashlock + 1; i++) | ||||||
| 		sx_destroy(&tqenthashtbl_lock[i]); | 		sx_destroy(&tqenthashtbl_lock[i]); | ||||||
| 	for (i = 0; i < tqenthash + 1; i++) | 	for (i = 0; i < tqenthash + 1; i++) | ||||||
| 		VERIFY(CK_LIST_EMPTY(&tqenthashtbl[i])); | 		VERIFY(LIST_EMPTY(&tqenthashtbl[i])); | ||||||
| 	free(tqenthashtbl_lock, M_TASKQ); | 	free(tqenthashtbl_lock, M_TASKQ); | ||||||
| 	free(tqenthashtbl, M_TASKQ); | 	free(tqenthashtbl, M_TASKQ); | ||||||
| } | } | ||||||
| @ -162,27 +160,27 @@ taskq_lookup(taskqid_t tqid) | |||||||
| { | { | ||||||
| 	taskq_ent_t *ent = NULL; | 	taskq_ent_t *ent = NULL; | ||||||
| 
 | 
 | ||||||
| 	sx_xlock(TQIDHASHLOCK(tqid)); | 	if (tqid == 0) | ||||||
| 	CK_LIST_FOREACH(ent, TQIDHASH(tqid), tqent_hash) { | 		return (NULL); | ||||||
|  | 	sx_slock(TQIDHASHLOCK(tqid)); | ||||||
|  | 	LIST_FOREACH(ent, TQIDHASH(tqid), tqent_hash) { | ||||||
| 		if (ent->tqent_id == tqid) | 		if (ent->tqent_id == tqid) | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| 	if (ent != NULL) | 	if (ent != NULL) | ||||||
| 		refcount_acquire(&ent->tqent_rc); | 		refcount_acquire(&ent->tqent_rc); | ||||||
| 	sx_xunlock(TQIDHASHLOCK(tqid)); | 	sx_sunlock(TQIDHASHLOCK(tqid)); | ||||||
| 	return (ent); | 	return (ent); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static taskqid_t | static taskqid_t | ||||||
| taskq_insert(taskq_ent_t *ent) | taskq_insert(taskq_ent_t *ent) | ||||||
| { | { | ||||||
| 	taskqid_t tqid; | 	taskqid_t tqid = __taskq_genid(); | ||||||
| 
 | 
 | ||||||
| 	tqid = __taskq_genid(); |  | ||||||
| 	ent->tqent_id = tqid; | 	ent->tqent_id = tqid; | ||||||
| 	ent->tqent_registered = B_TRUE; |  | ||||||
| 	sx_xlock(TQIDHASHLOCK(tqid)); | 	sx_xlock(TQIDHASHLOCK(tqid)); | ||||||
| 	CK_LIST_INSERT_HEAD(TQIDHASH(tqid), ent, tqent_hash); | 	LIST_INSERT_HEAD(TQIDHASH(tqid), ent, tqent_hash); | ||||||
| 	sx_xunlock(TQIDHASHLOCK(tqid)); | 	sx_xunlock(TQIDHASHLOCK(tqid)); | ||||||
| 	return (tqid); | 	return (tqid); | ||||||
| } | } | ||||||
| @ -192,13 +190,14 @@ taskq_remove(taskq_ent_t *ent) | |||||||
| { | { | ||||||
| 	taskqid_t tqid = ent->tqent_id; | 	taskqid_t tqid = ent->tqent_id; | ||||||
| 
 | 
 | ||||||
| 	if (!ent->tqent_registered) | 	if (tqid == 0) | ||||||
| 		return; | 		return; | ||||||
| 
 |  | ||||||
| 	sx_xlock(TQIDHASHLOCK(tqid)); | 	sx_xlock(TQIDHASHLOCK(tqid)); | ||||||
| 	CK_LIST_REMOVE(ent, tqent_hash); | 	if (ent->tqent_id != 0) { | ||||||
|  | 		LIST_REMOVE(ent, tqent_hash); | ||||||
|  | 		ent->tqent_id = 0; | ||||||
|  | 	} | ||||||
| 	sx_xunlock(TQIDHASHLOCK(tqid)); | 	sx_xunlock(TQIDHASHLOCK(tqid)); | ||||||
| 	ent->tqent_registered = B_FALSE; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| @ -285,21 +284,22 @@ taskq_cancel_id(taskq_t *tq, taskqid_t tid) | |||||||
| 	int rc; | 	int rc; | ||||||
| 	taskq_ent_t *ent; | 	taskq_ent_t *ent; | ||||||
| 
 | 
 | ||||||
| 	if (tid == 0) |  | ||||||
| 		return (0); |  | ||||||
| 
 |  | ||||||
| 	if ((ent = taskq_lookup(tid)) == NULL) | 	if ((ent = taskq_lookup(tid)) == NULL) | ||||||
| 		return (0); | 		return (0); | ||||||
| 
 | 
 | ||||||
| 	ent->tqent_cancelled = B_TRUE; | 	if (ent->tqent_type == NORMAL_TASK) { | ||||||
| 	if (ent->tqent_type == TIMEOUT_TASK) { | 		rc = taskqueue_cancel(tq->tq_queue, &ent->tqent_task, &pend); | ||||||
|  | 		if (rc == EBUSY) | ||||||
|  | 			taskqueue_drain(tq->tq_queue, &ent->tqent_task); | ||||||
|  | 	} else { | ||||||
| 		rc = taskqueue_cancel_timeout(tq->tq_queue, | 		rc = taskqueue_cancel_timeout(tq->tq_queue, | ||||||
| 		    &ent->tqent_timeout_task, &pend); | 		    &ent->tqent_timeout_task, &pend); | ||||||
| 	} else |  | ||||||
| 		rc = taskqueue_cancel(tq->tq_queue, &ent->tqent_task, &pend); |  | ||||||
| 		if (rc == EBUSY) { | 		if (rc == EBUSY) { | ||||||
| 		taskqueue_drain(tq->tq_queue, &ent->tqent_task); | 			taskqueue_drain_timeout(tq->tq_queue, | ||||||
| 	} else if (pend) { | 			    &ent->tqent_timeout_task); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (pend) { | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * Tasks normally free themselves when run, but here the task | 		 * Tasks normally free themselves when run, but here the task | ||||||
| 		 * was cancelled so it did not free itself. | 		 * was cancelled so it did not free itself. | ||||||
| @ -312,11 +312,12 @@ taskq_cancel_id(taskq_t *tq, taskqid_t tid) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| taskq_run(void *arg, int pending __unused) | taskq_run(void *arg, int pending) | ||||||
| { | { | ||||||
| 	taskq_ent_t *task = arg; | 	taskq_ent_t *task = arg; | ||||||
| 
 | 
 | ||||||
| 	if (!task->tqent_cancelled) | 	if (pending == 0) | ||||||
|  | 		return; | ||||||
| 	task->tqent_func(task->tqent_arg); | 	task->tqent_func(task->tqent_arg); | ||||||
| 	taskq_free(task); | 	taskq_free(task); | ||||||
| } | } | ||||||
| @ -345,7 +346,6 @@ taskq_dispatch_delay(taskq_t *tq, task_func_t func, void *arg, | |||||||
| 	task->tqent_func = func; | 	task->tqent_func = func; | ||||||
| 	task->tqent_arg = arg; | 	task->tqent_arg = arg; | ||||||
| 	task->tqent_type = TIMEOUT_TASK; | 	task->tqent_type = TIMEOUT_TASK; | ||||||
| 	task->tqent_cancelled = B_FALSE; |  | ||||||
| 	refcount_init(&task->tqent_rc, 1); | 	refcount_init(&task->tqent_rc, 1); | ||||||
| 	tqid = taskq_insert(task); | 	tqid = taskq_insert(task); | ||||||
| 	TIMEOUT_TASK_INIT(tq->tq_queue, &task->tqent_timeout_task, 0, | 	TIMEOUT_TASK_INIT(tq->tq_queue, &task->tqent_timeout_task, 0, | ||||||
| @ -379,7 +379,6 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags) | |||||||
| 	refcount_init(&task->tqent_rc, 1); | 	refcount_init(&task->tqent_rc, 1); | ||||||
| 	task->tqent_func = func; | 	task->tqent_func = func; | ||||||
| 	task->tqent_arg = arg; | 	task->tqent_arg = arg; | ||||||
| 	task->tqent_cancelled = B_FALSE; |  | ||||||
| 	task->tqent_type = NORMAL_TASK; | 	task->tqent_type = NORMAL_TASK; | ||||||
| 	tqid = taskq_insert(task); | 	tqid = taskq_insert(task); | ||||||
| 	TASK_INIT(&task->tqent_task, prio, taskq_run, task); | 	TASK_INIT(&task->tqent_task, prio, taskq_run, task); | ||||||
| @ -388,10 +387,12 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| taskq_run_ent(void *arg, int pending __unused) | taskq_run_ent(void *arg, int pending) | ||||||
| { | { | ||||||
| 	taskq_ent_t *task = arg; | 	taskq_ent_t *task = arg; | ||||||
| 
 | 
 | ||||||
|  | 	if (pending == 0) | ||||||
|  | 		return; | ||||||
| 	task->tqent_func(task->tqent_arg); | 	task->tqent_func(task->tqent_arg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -406,8 +407,6 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint32_t flags, | |||||||
| 	 * can go at the front of the queue. | 	 * can go at the front of the queue. | ||||||
| 	 */ | 	 */ | ||||||
| 	prio = !!(flags & TQ_FRONT); | 	prio = !!(flags & TQ_FRONT); | ||||||
| 	task->tqent_cancelled = B_FALSE; |  | ||||||
| 	task->tqent_registered = B_FALSE; |  | ||||||
| 	task->tqent_id = 0; | 	task->tqent_id = 0; | ||||||
| 	task->tqent_func = func; | 	task->tqent_func = func; | ||||||
| 	task->tqent_arg = arg; | 	task->tqent_arg = arg; | ||||||
| @ -427,12 +426,13 @@ taskq_wait_id(taskq_t *tq, taskqid_t tid) | |||||||
| { | { | ||||||
| 	taskq_ent_t *ent; | 	taskq_ent_t *ent; | ||||||
| 
 | 
 | ||||||
| 	if (tid == 0) |  | ||||||
| 		return; |  | ||||||
| 	if ((ent = taskq_lookup(tid)) == NULL) | 	if ((ent = taskq_lookup(tid)) == NULL) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	if (ent->tqent_type == NORMAL_TASK) | ||||||
| 		taskqueue_drain(tq->tq_queue, &ent->tqent_task); | 		taskqueue_drain(tq->tq_queue, &ent->tqent_task); | ||||||
|  | 	else | ||||||
|  | 		taskqueue_drain_timeout(tq->tq_queue, &ent->tqent_timeout_task); | ||||||
| 	taskq_free(ent); | 	taskq_free(ent); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Alexander Motin
						Alexander Motin