235 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * $Id$
 | |
|  *
 | |
|     Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| 
 | |
| #include "aio-prv.h"
 | |
| 
 | |
| #define HEAP_PARENT(x) (((x) - 1) / 2)
 | |
| #define HEAP_LEFT(x)   ((x) * 2 + 1)
 | |
| #define HEAP_RIGHT(x)  ((x) * 2 + 2)
 | |
| 
 | |
| #define YOUNGER_THAN(x,y) (qse_cmptime(&(x)->when, &(y)->when) < 0)
 | |
| 
 | |
| void qse_aio_cleartmrjobs (qse_aio_t* aio)
 | |
| {
 | |
| 	while (aio->tmr.size > 0) qse_aio_deltmrjob (aio, 0);
 | |
| }
 | |
| 
 | |
| static qse_aio_tmridx_t sift_up (qse_aio_t* aio, qse_aio_tmridx_t index, int notify)
 | |
| {
 | |
| 	qse_aio_tmridx_t parent;
 | |
| 
 | |
| 	parent = HEAP_PARENT(index);
 | |
| 	if (index > 0 && YOUNGER_THAN(&aio->tmr.jobs[index], &aio->tmr.jobs[parent]))
 | |
| 	{
 | |
| 		qse_aio_tmrjob_t item;
 | |
| 
 | |
| 		item = aio->tmr.jobs[index]; 
 | |
| 
 | |
| 		do
 | |
| 		{
 | |
| 			/* move down the parent to my current position */
 | |
| 			aio->tmr.jobs[index] = aio->tmr.jobs[parent];
 | |
| 			if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
 | |
| 
 | |
| 			/* traverse up */
 | |
| 			index = parent;
 | |
| 			parent = HEAP_PARENT(parent);
 | |
| 		}
 | |
| 		while (index > 0 && YOUNGER_THAN(&item, &aio->tmr.jobs[parent]));
 | |
| 
 | |
| 		aio->tmr.jobs[index] = item;
 | |
| 		if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
 | |
| 	}
 | |
| 
 | |
| 	return index;
 | |
| }
 | |
| 
 | |
| static qse_aio_tmridx_t sift_down (qse_aio_t* aio, qse_aio_tmridx_t index, int notify)
 | |
| {
 | |
| 	qse_size_t base = aio->tmr.size / 2;
 | |
| 
 | |
| 	if (index < base) /* at least 1 child is under the 'index' position */
 | |
| 	{
 | |
| 		qse_aio_tmrjob_t item;
 | |
| 
 | |
| 		item = aio->tmr.jobs[index];
 | |
| 
 | |
| 		do
 | |
| 		{
 | |
| 			qse_aio_tmridx_t left, right, younger;
 | |
| 
 | |
| 			left = HEAP_LEFT(index);
 | |
| 			right = HEAP_RIGHT(index);
 | |
| 
 | |
| 			if (right < aio->tmr.size && YOUNGER_THAN(&aio->tmr.jobs[right], &aio->tmr.jobs[left]))
 | |
| 			{
 | |
| 				younger = right;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				younger = left;
 | |
| 			}
 | |
| 
 | |
| 			if (YOUNGER_THAN(&item, &aio->tmr.jobs[younger])) break;
 | |
| 
 | |
| 			aio->tmr.jobs[index] = aio->tmr.jobs[younger];
 | |
| 			if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
 | |
| 
 | |
| 			index = younger;
 | |
| 		}
 | |
| 		while (index < base);
 | |
| 		
 | |
| 		aio->tmr.jobs[index] = item;
 | |
| 		if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
 | |
| 	}
 | |
| 
 | |
| 	return index;
 | |
| }
 | |
| 
 | |
| void qse_aio_deltmrjob (qse_aio_t* aio, qse_aio_tmridx_t index)
 | |
| {
 | |
| 	qse_aio_tmrjob_t item;
 | |
| 
 | |
| 	QSE_ASSERT (index < aio->tmr.size);
 | |
| 
 | |
| 	item = aio->tmr.jobs[index];
 | |
| 	if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = QSE_AIO_TMRIDX_INVALID;
 | |
| 
 | |
| 	aio->tmr.size = aio->tmr.size - 1;
 | |
| 	if (aio->tmr.size > 0 && index != aio->tmr.size)
 | |
| 	{
 | |
| 		aio->tmr.jobs[index] = aio->tmr.jobs[aio->tmr.size];
 | |
| 		if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
 | |
| 		YOUNGER_THAN(&aio->tmr.jobs[index], &item)? sift_up(aio, index, 1): sift_down(aio, index, 1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| qse_aio_tmridx_t qse_aio_instmrjob (qse_aio_t* aio, const qse_aio_tmrjob_t* job)
 | |
| {
 | |
| 	qse_aio_tmridx_t index = aio->tmr.size;
 | |
| 
 | |
| 	if (index >= aio->tmr.capa)
 | |
| 	{
 | |
| 		qse_aio_tmrjob_t* tmp;
 | |
| 		qse_size_t new_capa;
 | |
| 
 | |
| 		QSE_ASSERT (aio->tmr.capa >= 1);
 | |
| 		new_capa = aio->tmr.capa * 2;
 | |
| 		tmp = (qse_aio_tmrjob_t*)QSE_MMGR_REALLOC (aio->mmgr, aio->tmr.jobs, new_capa * QSE_SIZEOF(*tmp));
 | |
| 		if (tmp == QSE_NULL) 
 | |
| 		{
 | |
| 			aio->errnum = QSE_AIO_ENOMEM;
 | |
| 			return QSE_AIO_TMRIDX_INVALID;
 | |
| 		}
 | |
| 
 | |
| 		aio->tmr.jobs = tmp;
 | |
| 		aio->tmr.capa = new_capa;
 | |
| 	}
 | |
| 
 | |
| 	aio->tmr.size = aio->tmr.size + 1;
 | |
| 	aio->tmr.jobs[index] = *job;
 | |
| 	if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
 | |
| 	return sift_up (aio, index, 0);
 | |
| }
 | |
| 
 | |
| qse_aio_tmridx_t qse_aio_updtmrjob (qse_aio_t* aio, qse_aio_tmridx_t index, const qse_aio_tmrjob_t* job)
 | |
| {
 | |
| 	qse_aio_tmrjob_t item;
 | |
| 	item = aio->tmr.jobs[index];
 | |
| 	aio->tmr.jobs[index] = *job;
 | |
| 	if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
 | |
| 	return YOUNGER_THAN(job, &item)? sift_up (aio, index, 0): sift_down (aio, index, 0);
 | |
| }
 | |
| 
 | |
| void qse_aio_firetmrjobs (qse_aio_t* aio, const qse_ntime_t* tm, qse_size_t* firecnt)
 | |
| {
 | |
| 	qse_ntime_t now;
 | |
| 	qse_aio_tmrjob_t tmrjob;
 | |
| 	qse_size_t count = 0;
 | |
| 
 | |
| 	/* if the current time is not specified, get it from the system */
 | |
| 	if (tm) now = *tm;
 | |
| 	else qse_gettime (&now);
 | |
| 
 | |
| 	while (aio->tmr.size > 0)
 | |
| 	{
 | |
| 		if (qse_cmptime(&aio->tmr.jobs[0].when, &now) > 0) break;
 | |
| 
 | |
| 		tmrjob = aio->tmr.jobs[0]; /* copy the scheduled job */
 | |
| 		qse_aio_deltmrjob (aio, 0); /* deschedule the job */
 | |
| 
 | |
| 		count++;
 | |
| 		tmrjob.handler (aio, &now, &tmrjob); /* then fire the job */
 | |
| 	}
 | |
| 
 | |
| 	if (firecnt) *firecnt = count;
 | |
| }
 | |
| 
 | |
| int qse_aio_gettmrtmout (qse_aio_t* aio, const qse_ntime_t* tm, qse_ntime_t* tmout)
 | |
| {
 | |
| 	qse_ntime_t now;
 | |
| 
 | |
| 	/* time-out can't be calculated when there's no job scheduled */
 | |
| 	if (aio->tmr.size <= 0) 
 | |
| 	{
 | |
| 		aio->errnum = QSE_AIO_ENOENT;
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	/* if the current time is not specified, get it from the system */
 | |
| 	if (tm) now = *tm;
 | |
| 	else qse_gettime (&now);
 | |
| 
 | |
| 	qse_subtime (&aio->tmr.jobs[0].when, &now, tmout);
 | |
| 	if (tmout->sec < 0) qse_cleartime (tmout);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| qse_aio_tmrjob_t* qse_aio_gettmrjob (qse_aio_t* aio, qse_aio_tmridx_t index)
 | |
| {
 | |
| 	if (index < 0 || index >= aio->tmr.size)
 | |
| 	{
 | |
| 		aio->errnum = QSE_AIO_ENOENT;
 | |
| 		return QSE_NULL;
 | |
| 	}
 | |
| 
 | |
| 	return &aio->tmr.jobs[index];
 | |
| }
 | |
| 
 | |
| int qse_aio_gettmrjobdeadline (qse_aio_t* aio, qse_aio_tmridx_t index, qse_ntime_t* deadline)
 | |
| {
 | |
| 	if (index < 0 || index >= aio->tmr.size)
 | |
| 	{
 | |
| 		aio->errnum = QSE_AIO_ENOENT;
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	*deadline = aio->tmr.jobs[index].when;
 | |
| 	return 0;
 | |
| }
 |