1/*
2 * Copyright (C) 2004, 2005, 2007, 2011-2013  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id$ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <isc/mem.h>
25#include <isc/random.h>
26#include <isc/taskpool.h>
27#include <isc/util.h>
28
29/***
30 *** Types.
31 ***/
32
33struct isc_taskpool {
34	isc_mem_t *			mctx;
35	isc_taskmgr_t *			tmgr;
36	unsigned int			ntasks;
37	unsigned int			quantum;
38	isc_task_t **			tasks;
39};
40
41/***
42 *** Functions.
43 ***/
44
45static isc_result_t
46alloc_pool(isc_taskmgr_t *tmgr, isc_mem_t *mctx, unsigned int ntasks,
47	   unsigned int quantum, isc_taskpool_t **poolp)
48{
49	isc_taskpool_t *pool;
50	unsigned int i;
51
52	pool = isc_mem_get(mctx, sizeof(*pool));
53	if (pool == NULL)
54		return (ISC_R_NOMEMORY);
55
56	pool->mctx = NULL;
57	isc_mem_attach(mctx, &pool->mctx);
58	pool->ntasks = ntasks;
59	pool->quantum = quantum;
60	pool->tmgr = tmgr;
61	pool->tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
62	if (pool->tasks == NULL) {
63		isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool));
64		return (ISC_R_NOMEMORY);
65	}
66	for (i = 0; i < ntasks; i++)
67		pool->tasks[i] = NULL;
68
69	*poolp = pool;
70	return (ISC_R_SUCCESS);
71}
72
73isc_result_t
74isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx,
75		    unsigned int ntasks, unsigned int quantum,
76		    isc_taskpool_t **poolp)
77{
78	unsigned int i;
79	isc_taskpool_t *pool = NULL;
80	isc_result_t result;
81
82	INSIST(ntasks > 0);
83
84	/* Allocate the pool structure */
85	result = alloc_pool(tmgr, mctx, ntasks, quantum, &pool);
86	if (result != ISC_R_SUCCESS)
87		return (result);
88
89	/* Create the tasks */
90	for (i = 0; i < ntasks; i++) {
91		result = isc_task_create(tmgr, quantum, &pool->tasks[i]);
92		if (result != ISC_R_SUCCESS) {
93			isc_taskpool_destroy(&pool);
94			return (result);
95		}
96		isc_task_setname(pool->tasks[i], "taskpool", NULL);
97	}
98
99	*poolp = pool;
100	return (ISC_R_SUCCESS);
101}
102
103void
104isc_taskpool_gettask(isc_taskpool_t *pool, isc_task_t **targetp) {
105	isc_uint32_t i;
106	isc_random_get(&i);
107	isc_task_attach(pool->tasks[i % pool->ntasks], targetp);
108}
109
110int
111isc_taskpool_size(isc_taskpool_t *pool) {
112	REQUIRE(pool != NULL);
113	return (pool->ntasks);
114}
115
116isc_result_t
117isc_taskpool_expand(isc_taskpool_t **sourcep, unsigned int size,
118		    isc_taskpool_t **targetp)
119{
120	isc_result_t result;
121	isc_taskpool_t *pool;
122
123	REQUIRE(sourcep != NULL && *sourcep != NULL);
124	REQUIRE(targetp != NULL && *targetp == NULL);
125
126	pool = *sourcep;
127	if (size > pool->ntasks) {
128		isc_taskpool_t *newpool = NULL;
129		unsigned int i;
130
131		/* Allocate a new pool structure */
132		result = alloc_pool(pool->tmgr, pool->mctx, size,
133				    pool->quantum, &newpool);
134		if (result != ISC_R_SUCCESS)
135			return (result);
136
137		/* Copy over the tasks from the old pool */
138		for (i = 0; i < pool->ntasks; i++) {
139			newpool->tasks[i] = pool->tasks[i];
140			pool->tasks[i] = NULL;
141		}
142
143		/* Create new tasks */
144		for (i = pool->ntasks; i < size; i++) {
145			result = isc_task_create(pool->tmgr, pool->quantum,
146						 &newpool->tasks[i]);
147			if (result != ISC_R_SUCCESS) {
148				isc_taskpool_destroy(&newpool);
149				return (result);
150			}
151			isc_task_setname(newpool->tasks[i], "taskpool", NULL);
152		}
153
154		isc_taskpool_destroy(&pool);
155		pool = newpool;
156	}
157
158	*sourcep = NULL;
159	*targetp = pool;
160	return (ISC_R_SUCCESS);
161}
162
163void
164isc_taskpool_destroy(isc_taskpool_t **poolp) {
165	unsigned int i;
166	isc_taskpool_t *pool = *poolp;
167	for (i = 0; i < pool->ntasks; i++) {
168		if (pool->tasks[i] != NULL)
169			isc_task_detach(&pool->tasks[i]);
170	}
171	isc_mem_put(pool->mctx, pool->tasks,
172		    pool->ntasks * sizeof(isc_task_t *));
173	isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool));
174	*poolp = NULL;
175}
176
177void
178isc_taskpool_setprivilege(isc_taskpool_t *pool, isc_boolean_t priv) {
179	unsigned int i;
180
181	REQUIRE(pool != NULL);
182
183	for (i = 0; i < pool->ntasks; i++) {
184		if (pool->tasks[i] != NULL)
185			isc_task_setprivilege(pool->tasks[i], priv);
186	}
187}
188