mempool.c 10.5 KB
Newer Older
1
/*
B
bernard.xiong 已提交
2
 * File      : mempool.c
3
 * This file is part of RT-Thread RTOS
D
dzzxzz 已提交
4
 * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
5 6 7
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
B
bernard.xiong 已提交
8
 * http://www.rt-thread.org/license/LICENSE
9 10 11 12
 *
 * Change Logs:
 * Date           Author       Notes
 * 2006-05-27     Bernard      implement memory pool
B
bernard.xiong 已提交
13
 * 2006-06-03     Bernard      fix the thread timer init bug
14 15 16
 * 2006-06-30     Bernard      fix the allocate/free block bug
 * 2006-08-04     Bernard      add hook support
 * 2006-08-10     Bernard      fix interrupt bug in rt_mp_alloc
17
 * 2010-07-13     Bernard      fix RT_ALIGN issue found by kuronca
qiuyiuestc's avatar
qiuyiuestc 已提交
18
 * 2010-10-26     yi.qiu       add module support in rt_mp_delete
19
 * 2011-01-24     Bernard      add object allocation check.
20
 * 2012-03-22     Bernard      fix align issue in rt_mp_init and rt_mp_create.
21 22 23 24 25 26 27 28
 */

#include <rthw.h>
#include <rtthread.h>

#ifdef RT_USING_MEMPOOL

#ifdef RT_USING_HOOK
D
dzzxzz 已提交
29 30
static void (*rt_mp_alloc_hook)(struct rt_mempool *mp, void *block);
static void (*rt_mp_free_hook)(struct rt_mempool *mp, void *block);
31 32 33 34

/**
 * @addtogroup Hook
 */
D
dzzxzz 已提交
35

36 37 38 39 40
/*@{*/

/**
 * This function will set a hook function, which will be invoked when a memory
 * block is allocated from memory pool.
B
bernard.xiong 已提交
41
 *
42 43
 * @param hook the hook function
 */
D
dzzxzz 已提交
44
void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block))
45 46 47 48 49 50 51
{
	rt_mp_alloc_hook = hook;
}

/**
 * This function will set a hook function, which will be invoked when a memory
 * block is released to memory pool.
B
bernard.xiong 已提交
52
 *
53 54
 * @param hook the hook function
 */
D
dzzxzz 已提交
55
void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block))
56 57 58 59 60 61 62 63 64 65 66 67 68 69
{
	rt_mp_free_hook = hook;
}

/*@}*/
#endif

/**
 * @addtogroup MM
 */

/*@{*/

/**
B
bernard.xiong@gmail.com 已提交
70 71
 * This function will initialize a memory pool object, normally which is used for
 * static object.
72
 *
B
bernard.xiong@gmail.com 已提交
73
 * @param mp the memory pool object
74 75 76 77 78
 * @param name the name of memory pool
 * @param start the star address of memory pool
 * @param size the total size of memory pool
 * @param block_size the size for each block
 *
B
bernard.xiong@gmail.com 已提交
79
 * @return RT_EOK
80
 */
D
dzzxzz 已提交
81
rt_err_t rt_mp_init(struct rt_mempool *mp, const char *name, void *start, rt_size_t size, rt_size_t block_size)
82 83 84 85 86 87 88
{
	rt_uint8_t *block_ptr;
	register rt_base_t offset;

	/* parameter check */
	RT_ASSERT(mp != RT_NULL);

89
	/* initialize object */
90 91
	rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name);

92
	/* initialize memory pool */
93
	mp->start_address = start;
94
	mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
95

96 97
	/* align the block size */
	block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
98 99 100
	mp->block_size = block_size;

	/* align to align size byte */
D
dzzxzz 已提交
101
	mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *));
102 103
	mp->block_free_count = mp->block_total_count;

104
	/* initialize suspended thread list */
105 106 107
	rt_list_init(&(mp->suspend_thread));
	mp->suspend_thread_count = 0;

108
	/* initialize free block list */
D
dzzxzz 已提交
109
	block_ptr = (rt_uint8_t *)mp->start_address;
110 111
	for (offset = 0; offset < mp->block_total_count; offset ++)
	{
D
dzzxzz 已提交
112 113
		*(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *)))
			= (rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)));
114 115
	}

D
dzzxzz 已提交
116
	*(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = RT_NULL;
117 118 119 120 121

	mp->block_list = block_ptr;

	return RT_EOK;
}
122
RTM_EXPORT(rt_mp_init);
123

B
bernard.xiong@gmail.com 已提交
124 125 126 127 128 129 130
/**
 * This function will detach a memory pool from system object management.
 *
 * @param mp the memory pool object
 *
 * @return RT_EOK
 */
D
dzzxzz 已提交
131
rt_err_t rt_mp_detach(struct rt_mempool *mp)
132
{
D
dzzxzz 已提交
133
	struct rt_thread *thread;
134 135 136 137 138
	register rt_ubase_t temp;

	/* parameter check */
	RT_ASSERT(mp != RT_NULL);

139
	/* wake up all suspended threads */
140 141 142 143 144 145 146 147 148 149 150
	while (!rt_list_isempty(&(mp->suspend_thread)))
	{
		/* disable interrupt */
		temp = rt_hw_interrupt_disable();

		/* get next suspend thread */
		thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
		/* set error code to RT_ERROR */
		thread->error = -RT_ERROR;

		/*
B
bernard.xiong 已提交
151
		 * resume thread
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
		 * In rt_thread_resume function, it will remove current thread from suspend
		 * list
		 */
		rt_thread_resume(thread);

		/* decrease suspended thread count */
		mp->suspend_thread_count --;

		/* enable interrupt */
		rt_hw_interrupt_enable(temp);
	}

	/* detach object */
	rt_object_detach(&(mp->parent));

	return RT_EOK;
}
169
RTM_EXPORT(rt_mp_detach);
170 171 172 173 174 175 176 177 178 179 180

#ifdef RT_USING_HEAP
/**
 * This function will create a mempool object and allocate the memory pool from heap.
 *
 * @param name the name of memory pool
 * @param block_count the count of blocks in memory pool
 * @param block_size the size for each block
 *
 * @return the created mempool object
 */
D
dzzxzz 已提交
181
rt_mp_t rt_mp_create(const char *name, rt_size_t block_count, rt_size_t block_size)
182 183
{
	rt_uint8_t *block_ptr;
D
dzzxzz 已提交
184
	struct rt_mempool *mp;
185 186
	register rt_base_t offset;

187
	RT_DEBUG_NOT_IN_INTERRUPT;
188

189
	/* allocate object */
D
dzzxzz 已提交
190
	mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name);
D
dzzxzz 已提交
191 192
	if (mp == RT_NULL)
		return RT_NULL; /* allocate object failed */
193

194 195 196
	/* initialize memory pool */
	block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
	mp->block_size = block_size;
D
dzzxzz 已提交
197
	mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count;
198 199

	/* allocate memory */
D
dzzxzz 已提交
200
	mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) * block_count);
201 202 203 204 205 206 207 208 209 210 211
	if (mp->start_address == RT_NULL)
	{
		/* no memory, delete memory pool object */
		rt_object_delete(&(mp->parent));

		return RT_NULL;
	}

	mp->block_total_count = block_count;
	mp->block_free_count = mp->block_total_count;

212
	/* initialize suspended thread list */
213 214 215
	rt_list_init(&(mp->suspend_thread));
	mp->suspend_thread_count = 0;

216
	/* initialize free block list */
D
dzzxzz 已提交
217
	block_ptr = (rt_uint8_t *)mp->start_address;
218 219
	for (offset = 0; offset < mp->block_total_count; offset ++)
	{
D
dzzxzz 已提交
220 221
		*(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *)))
			= block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *));
222 223
	}

D
dzzxzz 已提交
224
	*(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = RT_NULL;
225 226 227 228 229

	mp->block_list = block_ptr;

	return mp;
}
230
RTM_EXPORT(rt_mp_create);
231 232 233 234 235 236

/**
 * This function will delete a memory pool and release the object memory.
 *
 * @param mp the memory pool object
 *
B
bernard.xiong@gmail.com 已提交
237
 * @return RT_EOK
238 239 240
 */
rt_err_t rt_mp_delete(rt_mp_t mp)
{
D
dzzxzz 已提交
241
	struct rt_thread *thread;
242 243
	register rt_ubase_t temp;

244
	RT_DEBUG_NOT_IN_INTERRUPT;
245

246 247 248
	/* parameter check */
	RT_ASSERT(mp != RT_NULL);

249
	/* wake up all suspended threads */
250 251 252 253 254 255 256 257 258 259 260
	while (!rt_list_isempty(&(mp->suspend_thread)))
	{
		/* disable interrupt */
		temp = rt_hw_interrupt_disable();

		/* get next suspend thread */
		thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
		/* set error code to RT_ERROR */
		thread->error = -RT_ERROR;

		/*
B
bernard.xiong 已提交
261
		 * resume thread
262 263 264 265 266 267 268 269 270 271 272 273
		 * In rt_thread_resume function, it will remove current thread from suspend
		 * list
		 */
		rt_thread_resume(thread);

		/* decrease suspended thread count */
		mp->suspend_thread_count --;

		/* enable interrupt */
		rt_hw_interrupt_enable(temp);
	}

qiuyiuestc's avatar
qiuyiuestc 已提交
274
#if defined(RT_USING_MODULE) && defined(RT_USING_SLAB)
qiuyiuestc's avatar
qiuyiuestc 已提交
275
	/* the mp object belongs to an application module */
D
dzzxzz 已提交
276
	if (mp->parent.flag & RT_OBJECT_FLAG_MODULE) 
qiuyiuestc's avatar
qiuyiuestc 已提交
277 278 279 280
		rt_module_free(mp->parent.module_id, mp->start_address);
	else
#endif

281 282
	/* release allocated room */
	rt_free(mp->start_address);
B
bernard.xiong 已提交
283

284 285 286 287 288
	/* detach object */
	rt_object_delete(&(mp->parent));

	return RT_EOK;
}
289
RTM_EXPORT(rt_mp_delete);
290 291 292 293 294 295 296 297
#endif

/**
 * This function will allocate a block from memory pool
 *
 * @param mp the memory pool object
 * @param time the waiting time
 *
B
bernard.xiong@gmail.com 已提交
298
 * @return the allocated memory block or RT_NULL on allocated failed
299
 */
D
dzzxzz 已提交
300
void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
301
{
D
dzzxzz 已提交
302
	rt_uint8_t *block_ptr;
303
	register rt_base_t level;
D
dzzxzz 已提交
304
	struct rt_thread *thread;
B
bernard.xiong 已提交
305

306 307 308
	/* disable interrupt */
	level = rt_hw_interrupt_disable();

D
dzzxzz 已提交
309
	if (mp->block_free_count)
310 311
	{
		/* memory block is available. decrease the free block counter */
D
dzzxzz 已提交
312
		mp->block_free_count --;
313 314 315

		/* get block from block list */
		block_ptr = mp->block_list;
D
dzzxzz 已提交
316
		mp->block_list = *(rt_uint8_t **)block_ptr;
317 318

		/* point to memory pool */
D
dzzxzz 已提交
319
		*(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
320 321 322 323
	}
	else
	{
		/* memory block is unavailable. */
324 325
		if (time == 0)
		{
B
bernard.xiong 已提交
326 327
			/* enable interrupt */
			rt_hw_interrupt_enable(level);
328
			return RT_NULL;
B
bernard.xiong 已提交
329
		}
330 331
		else
		{
332
			RT_DEBUG_NOT_IN_INTERRUPT;
333

334 335 336 337 338 339
			/* get current thread */
			thread = rt_thread_self();

			/* need suspend thread */
			rt_thread_suspend(thread);
			rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
D
dzzxzz 已提交
340
			mp->suspend_thread_count ++;
341 342 343 344 345

			if (time > 0)
			{
				/* init thread timer and start it */
				rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time);
B
bernard.xiong 已提交
346
				rt_timer_start(&(thread->thread_timer));
347 348 349 350 351 352 353 354
			}

			/* enable interrupt */
			rt_hw_interrupt_enable(level);

			/* do a schedule */
			rt_schedule();

D
dzzxzz 已提交
355 356
			if (thread->error != RT_EOK)
				return RT_NULL;
357 358 359 360 361 362 363 364 365

			/* disable interrupt */
			level = rt_hw_interrupt_disable();

			/* decrease free block */
			mp->block_free_count --;

			/* get block from block list */
			block_ptr = mp->block_list;
D
dzzxzz 已提交
366
			mp->block_list = *(rt_uint8_t **)block_ptr;
367 368

			/* point to memory pool */
D
dzzxzz 已提交
369
			*(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
370 371 372 373 374 375
		}
	}

	/* enable interrupt */
	rt_hw_interrupt_enable(level);

D
dzzxzz 已提交
376
	RT_OBJECT_HOOK_CALL(rt_mp_alloc_hook, (mp, (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *))));
377

D
dzzxzz 已提交
378
	return (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *));
379
}
380
RTM_EXPORT(rt_mp_alloc);
381 382 383 384 385 386

/**
 * This function will release a memory block
 *
 * @param block the address of memory block to be released
 */
D
dzzxzz 已提交
387
void rt_mp_free(void *block)
388 389 390 391 392 393 394
{
	rt_uint8_t **block_ptr;
	struct rt_mempool *mp;
	struct rt_thread *thread;
	register rt_base_t level;

	/* get the control block of pool which the block belongs to */
D
dzzxzz 已提交
395 396
	block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *));
	mp = (struct rt_mempool *)*block_ptr;
397

398
	RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block));
399 400 401 402 403 404 405 406 407

	/* disable interrupt */
	level = rt_hw_interrupt_disable();

	/* increase the free block count */
	mp->block_free_count ++;

	/* link the block into the block list */
	*block_ptr = mp->block_list;
D
dzzxzz 已提交
408
	mp->block_list = (rt_uint8_t *)block_ptr;
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435

	if (mp->suspend_thread_count > 0)
	{
		/* get the suspended thread */
		thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);

		/* set error */
		thread->error = RT_EOK;

		/* resume thread */
		rt_thread_resume(thread);

		/* decrease suspended thread count */
		mp->suspend_thread_count --;

		/* enable interrupt */
		rt_hw_interrupt_enable(level);

		/* do a schedule */
		rt_schedule();

		return;
	}

	/* enable interrupt */
	rt_hw_interrupt_enable(level);
}
436
RTM_EXPORT(rt_mp_free);
437 438 439

/*@}*/

D
dzzxzz 已提交
440 441
#endif