⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mutex.c

📁 uT Kernel os source code for AT91
💻 C
字号:
/* *---------------------------------------------------------------------- *    micro T-Kernel * *    Copyright (C) 2006-2007 by Ken Sakamura. All rights reserved. *    micro T-Kernel is distributed under the micro T-License. *---------------------------------------------------------------------- * *    Version:   1.00.00 *    Released by T-Engine Forum(http://www.t-engine.org) at 2007/03/26. * *---------------------------------------------------------------------- *//* *	mutex.c *	Mutex *//** [BEGIN Common Definitions] */#include "kernel.h"#include "task.h"#include "wait.h"#include "check.h"#include "mutex.h"/** [END Common Definitions] */#if CFN_MAX_MTXID > 0#ifdef USE_FUNC_MTXCB_TABLENoinit(EXPORT MTXCB	knl_mtxcb_table[NUM_MTXID]);	/* Mutex control block */Noinit(EXPORT QUEUE	knl_free_mtxcb);	/* FreeQue */#endif /* USE_FUNC_MTXCB_TABLE */#ifdef USE_FUNC_MUTEX_INITIALIZE/* * Initialization of mutex control block  */EXPORT ER knl_mutex_initialize(void){	MTXCB	*mtxcb, *end;	/* Get system information */	if ( NUM_MTXID < 1 ) {		return E_SYS;	}	/* Register all control blocks onto FreeQue */	QueInit(&knl_free_mtxcb);	end = knl_mtxcb_table + NUM_MTXID;	for( mtxcb = knl_mtxcb_table; mtxcb < end; mtxcb++ ) {		mtxcb->mtxid = 0;		QueInsert(&mtxcb->wait_queue, &knl_free_mtxcb);	}	return E_OK;}#endif /* USE_FUNC_MUTEX_INITIALIZE */#ifdef USE_FUNC_RELEASE_MUTEX/* * Release the lock and delete it from list, and then adjust the * priority of task. * Set the highest priority between listed below: *	(A) The highest priority in all mutexes in which 'tcb' task locks.  *	(B) The base priority of 'tcb' task. */EXPORT void knl_release_mutex( TCB *tcb, MTXCB *relmtxcb ){	MTXCB	*mtxcb, **prev;	INT	newpri, pri;	/* (B) The base priority of task */	newpri = tcb->bpriority;	/* (A) The highest priority in mutex which is locked */	pri = newpri;	prev = &tcb->mtxlist;	while ( (mtxcb = *prev) != NULL ) {		if ( mtxcb == relmtxcb ) {			/* Delete from list */			*prev = mtxcb->mtxlist;			continue;		}		switch ( mtxcb->mtxatr & TA_CEILING ) {		  case TA_CEILING:			pri = mtxcb->ceilpri;			break;		  case TA_INHERIT:			if ( mtx_waited(mtxcb) ) {				pri = mtx_head_pri(mtxcb);			}			break;		  default: /* TA_TFIFO, TA_TPRI */			/* nothing to do */			break;		}		if ( newpri > pri ) {			newpri = pri;		}		prev = &mtxcb->mtxlist;	}	if ( newpri != tcb->priority ) {		/* Change priority of lock get task */		knl_change_task_priority(tcb, newpri);	}}#endif /* USE_FUNC_RELEASE_MUTEX */#ifdef USE_FUNC_SIGNAL_ALL_MUTEX/* * Free mutex when task is terminated *	Free all mutexes which the task holds. *	Do not need to handle mutex list and priority of terminated task. *	 */EXPORT void knl_signal_all_mutex( TCB *tcb ){	MTXCB	*mtxcb, *next_mtxcb;	TCB	*next_tcb;	next_mtxcb = tcb->mtxlist;	while ( (mtxcb = next_mtxcb) != NULL ) {		next_mtxcb = mtxcb->mtxlist;		if ( mtx_waited(mtxcb) ) {			next_tcb = (TCB*)mtxcb->wait_queue.next;			/* Wake wait task */			knl_wait_release_ok(next_tcb);			/* Change mutex get task */			mtxcb->mtxtsk = next_tcb;			mtxcb->mtxlist = next_tcb->mtxlist;			next_tcb->mtxlist = mtxcb;			if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) {				if ( next_tcb->priority > mtxcb->ceilpri ) {					/* Raise the priority for the task					   that got lock to the highest					   priority limit */					knl_change_task_priority(next_tcb,							mtxcb->ceilpri);				}			}		} else {			/* No wait task */			mtxcb->mtxtsk = NULL;		}	}}#endif /* USE_FUNC_SIGNAL_ALL_MUTEX */#ifdef USE_FUNC_CHG_PRI_MUTEX/* * Limit the priority change by mutex at task priority change *    1.If the 'tcb' task locks mutex, cannot set lower priority than the  *	highest priority in all mutexes which hold lock. In such case,  *	return the highest priority of locked mutex.  *    2.If mutex with TA_CEILING attribute is locked or waiting to be locked,  *	cannot set higher priority than the lowest within the highest  *	priority limit of mutex with TA_CEILING attribute. *	In this case, return E_ILUSE. *    3.Other than above, return the 'priority'. */EXPORT INT knl_chg_pri_mutex( TCB *tcb, INT priority ){	MTXCB	*mtxcb;	INT	hi_pri, low_pri, pri;	hi_pri  = priority;	low_pri = int_priority(MIN_PRI);	/* Mutex lock wait */	if ( (tcb->state & TS_WAIT) != 0 && (tcb->wspec->tskwait & TTW_MTX) != 0 ) {		mtxcb = get_mtxcb(tcb->wid);		if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) {			pri = mtxcb->ceilpri;			if ( pri > low_pri ) {				low_pri = pri;			}		}	}	/* Locked Mutex */	pri = hi_pri;	for ( mtxcb = tcb->mtxlist; mtxcb != NULL; mtxcb = mtxcb->mtxlist ) {		switch ( mtxcb->mtxatr & TA_CEILING ) {		  case TA_CEILING:			pri = mtxcb->ceilpri;			if ( pri > low_pri ) {				low_pri = pri;			}			break;		  case TA_INHERIT:			if ( mtx_waited(mtxcb) ) {				pri = mtx_head_pri(mtxcb);			}			break;		  default: /* TA_TFIFO, TA_TPRI */			/* nothing to do */			break;		}		if ( pri < hi_pri ) {			hi_pri = pri;		}	}	if ( priority < low_pri ) {		return E_ILUSE;	}	return hi_pri;}#endif /* USE_FUNC_CHG_PRI_MUTEX */#ifdef USE_FUNC_TK_CRE_MTX/* * Create mutex */SYSCALL ID tk_cre_mtx_impl( T_CMTX *pk_cmtx ){	const ATR VALID_MTXATR = {		 TA_CEILING#if USE_OBJECT_NAME		|TA_DSNAME#endif	};	MTXCB	*mtxcb;	ID	mtxid;	INT	ceilpri;	ER	ercd;	CHECK_RSATR(pk_cmtx->mtxatr, VALID_MTXATR);	if ( (pk_cmtx->mtxatr & TA_CEILING) == TA_CEILING ) {		CHECK_PRI(pk_cmtx->ceilpri);		ceilpri = int_priority(pk_cmtx->ceilpri);	} else {		ceilpri = 0;	}	BEGIN_CRITICAL_SECTION;	/* Get control block from FreeQue */	mtxcb = (MTXCB*)QueRemoveNext(&knl_free_mtxcb);	if ( mtxcb == NULL ) {		ercd = E_LIMIT;	} else {		mtxid = ID_MTX(mtxcb - knl_mtxcb_table);		/* Initialize control block */		QueInit(&mtxcb->wait_queue);		mtxcb->mtxid   = mtxid;		mtxcb->exinf   = pk_cmtx->exinf;		mtxcb->mtxatr  = pk_cmtx->mtxatr;		mtxcb->ceilpri = ceilpri;		mtxcb->mtxtsk  = NULL;		mtxcb->mtxlist = NULL;#if USE_OBJECT_NAME		if ( (pk_cmtx->mtxatr & TA_DSNAME) != 0 ) {			strncpy((char*)mtxcb->name, (char*)pk_cmtx->dsname,				(UINT)OBJECT_NAME_LENGTH);		}#endif		ercd = mtxid;	}	END_CRITICAL_SECTION;	return ercd;}#endif /* USE_FUNC_TK_CRE_MTX */#ifdef USE_FUNC_TK_DEL_MTX/* * Delete mutex */SYSCALL ER tk_del_mtx_impl( ID mtxid ){	MTXCB	*mtxcb;	ER	ercd = E_OK;	CHECK_MTXID(mtxid);	mtxcb = get_mtxcb(mtxid);	BEGIN_CRITICAL_SECTION;	if ( mtxcb->mtxid == 0 ) {		ercd = E_NOEXS;	} else {		/* If there is a task that holds mutex to delete,		 * delete the mutex from the list		 * and adjust the task priority if necessary.		 */		if ( mtxcb->mtxtsk != NULL ) {			knl_release_mutex(mtxcb->mtxtsk, mtxcb);		}		/* Free wait state of task (E_DLT) */		knl_wait_delete(&mtxcb->wait_queue);		/* Return to FreeQue */		QueInsert(&mtxcb->wait_queue, &knl_free_mtxcb);		mtxcb->mtxid = 0;	}	END_CRITICAL_SECTION;	return ercd;}#endif /* USE_FUNC_TK_DEL_MTX */#ifdef USE_FUNC_TK_LOC_MTX/* * Processing if the priority of wait task changes */LOCAL void mtx_chg_pri( TCB *tcb, INT oldpri ){	MTXCB	*mtxcb;	TCB	*mtxtsk;	mtxcb = get_mtxcb(tcb->wid);	knl_gcb_change_priority((GCB*)mtxcb, tcb);	if ( (mtxcb->mtxatr & TA_CEILING) == TA_INHERIT ) {		mtxtsk = mtxcb->mtxtsk;		if ( mtxtsk->priority > tcb->priority ) {			/* Since the highest priority of the lock wait task			   became higher, raise the lock get task priority			   higher */			knl_change_task_priority(mtxtsk, tcb->priority);		} else if ( mtxtsk->priority == oldpri ) {			/* Since the highest priority of the lock wait task			   might become lower, adjust this priority */			reset_priority(mtxtsk);		}	}}/* * Processing if the wait task is released (For TA_INHERIT only) */LOCAL void mtx_rel_wai( TCB *tcb ){	MTXCB	*mtxcb;	TCB	*mtxtsk;	mtxcb = get_mtxcb(tcb->wid);	mtxtsk = mtxcb->mtxtsk;	if ( mtxtsk->priority == tcb->priority ) {		/* Since the highest priority of the lock wait task might 		   become lower, adjust this priority */		reset_priority(mtxtsk);	}}/* * Definition of mutex wait specification */LOCAL WSPEC knl_wspec_mtx_tfifo   = { TTW_MTX, NULL, NULL };LOCAL WSPEC knl_wspec_mtx_tpri    = { TTW_MTX, mtx_chg_pri, NULL };LOCAL WSPEC knl_wspec_mtx_inherit = { TTW_MTX, mtx_chg_pri, mtx_rel_wai };/* * Lock mutex */SYSCALL ER tk_loc_mtx_impl( ID mtxid, TMO tmout ){	MTXCB	*mtxcb;	TCB	*mtxtsk;	ATR	mtxatr;	ER	ercd = E_OK;	CHECK_MTXID(mtxid);	CHECK_TMOUT(tmout);	CHECK_DISPATCH();	mtxcb = get_mtxcb(mtxid);	BEGIN_CRITICAL_SECTION;	if ( mtxcb->mtxid == 0 ) {		ercd = E_NOEXS;		goto error_exit;	}	if ( mtxcb->mtxtsk == knl_ctxtsk ) {		ercd = E_ILUSE;  /* Multiplexed lock */		goto error_exit;	}	mtxatr = mtxcb->mtxatr & TA_CEILING;	if ( mtxatr == TA_CEILING ) {		if ( knl_ctxtsk->bpriority < mtxcb->ceilpri ) {			/* Violation of highest priority limit */			ercd = E_ILUSE;			goto error_exit;		}	}	mtxtsk = mtxcb->mtxtsk;	if ( mtxtsk == NULL ) {		/* Get lock */		mtxcb->mtxtsk = knl_ctxtsk;		mtxcb->mtxlist = knl_ctxtsk->mtxlist;		knl_ctxtsk->mtxlist = mtxcb;		if ( mtxatr == TA_CEILING ) {			if ( knl_ctxtsk->priority > mtxcb->ceilpri ) {				/* Raise its own task to the highest				   priority limit */				knl_change_task_priority(knl_ctxtsk, mtxcb->ceilpri);			}		}	} else {		ercd = E_TMOUT;		if ( tmout == TMO_POL ) {			goto error_exit;		}		if ( mtxatr == TA_INHERIT ) {			if ( mtxtsk->priority > knl_ctxtsk->priority ) {				/* Raise the priority of task during				   locking to the same priority as its				   own task */				knl_change_task_priority(mtxtsk, knl_ctxtsk->priority);			}		}		/* Ready for wait */		knl_ctxtsk->wspec = ( mtxatr == TA_TFIFO   )? &knl_wspec_mtx_tfifo:				( mtxatr == TA_INHERIT )? &knl_wspec_mtx_inherit:							  &knl_wspec_mtx_tpri;		knl_ctxtsk->wercd = &ercd;		knl_ctxtsk->wid = mtxcb->mtxid;		knl_make_wait(tmout, mtxcb->mtxatr);		if ( mtxatr == TA_TFIFO ) {			QueInsert(&knl_ctxtsk->tskque, &mtxcb->wait_queue);		} else {			knl_queue_insert_tpri(knl_ctxtsk, &mtxcb->wait_queue);		}	}    error_exit:	END_CRITICAL_SECTION;	return ercd;}#endif /* USE_FUNC_TK_LOC_MTX */#ifdef USE_FUNC_TK_UNL_MTX/* * Unlock mutex */SYSCALL ER tk_unl_mtx_impl( ID mtxid ){	MTXCB	*mtxcb;		TCB	*tcb;	ER	ercd = E_OK;	CHECK_MTXID(mtxid);	CHECK_INTSK();	mtxcb = get_mtxcb(mtxid);	BEGIN_CRITICAL_SECTION;	if ( mtxcb->mtxid == 0 ) {		ercd = E_NOEXS;		goto error_exit;	}	if ( mtxcb->mtxtsk != knl_ctxtsk ) {		ercd = E_ILUSE;  /* This is not locked by its own task */		goto error_exit;	}	/* Delete the mutex from the list,	   and adjust its own task priority if necessary. */	knl_release_mutex(knl_ctxtsk, mtxcb);	if ( mtx_waited(mtxcb) ) {		tcb = (TCB*)mtxcb->wait_queue.next;		/* Release wait */		knl_wait_release_ok(tcb);		/* Change mutex get task */		mtxcb->mtxtsk = tcb;		mtxcb->mtxlist = tcb->mtxlist;		tcb->mtxlist = mtxcb;		if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) {			if ( tcb->priority > mtxcb->ceilpri ) {				/* Raise the priority of the task that				   got lock to the highest priority limit */				knl_change_task_priority(tcb, mtxcb->ceilpri);			}		}	} else {		/* No wait task */		mtxcb->mtxtsk = NULL;	}    error_exit:	END_CRITICAL_SECTION;	return ercd;}#endif /* USE_FUNC_TK_UNL_MTX */#ifdef USE_FUNC_TK_REF_MTX/* * Refer mutex state */SYSCALL ER tk_ref_mtx_impl( ID mtxid, T_RMTX *pk_rmtx ){	MTXCB	*mtxcb;	ER	ercd = E_OK;	CHECK_MTXID(mtxid);	mtxcb = get_mtxcb(mtxid);	BEGIN_CRITICAL_SECTION;	if ( mtxcb->mtxid == 0 ) {		ercd = E_NOEXS;	} else {		pk_rmtx->exinf = mtxcb->exinf;		pk_rmtx->htsk = ( mtxcb->mtxtsk != NULL )?					mtxcb->mtxtsk->tskid: 0;		pk_rmtx->wtsk = knl_wait_tskid(&mtxcb->wait_queue);	}	END_CRITICAL_SECTION;	return ercd;}#endif /* USE_FUNC_TK_REF_MTX *//* ------------------------------------------------------------------------ *//* *	Debugger support function */#if USE_DBGSPT#ifdef USE_FUNC_MUTEX_GETNAME#if USE_OBJECT_NAME/* * Get object name from control block */EXPORT ER knl_mutex_getname(ID id, UB **name){	MTXCB	*mtxcb;	ER	ercd = E_OK;	CHECK_MTXID(id);	BEGIN_DISABLE_INTERRUPT;	mtxcb = get_mtxcb(id);	if ( mtxcb->mtxid == 0 ) {		ercd = E_NOEXS;		goto error_exit;	}	if ( (mtxcb->mtxatr & TA_DSNAME) == 0 ) {		ercd = E_OBJ;		goto error_exit;	}	*name = mtxcb->name;    error_exit:	END_DISABLE_INTERRUPT;	return ercd;}#endif /* USE_OBJECT_NAME */#endif /* USE_FUNC_MUTEX_GETNAME */#ifdef USE_FUNC_TD_LST_MTX/* * Refer mutex usage state */SYSCALL INT td_lst_mtx_impl( ID list[], INT nent ){	MTXCB	*mtxcb, *end;	INT	n = 0;	BEGIN_DISABLE_INTERRUPT;	end = knl_mtxcb_table + NUM_MTXID;	for ( mtxcb = knl_mtxcb_table; mtxcb < end; mtxcb++ ) {		if ( mtxcb->mtxid == 0 ) {			continue;		}		if ( n++ < nent ) {			*list++ = mtxcb->mtxid;		}	}	END_DISABLE_INTERRUPT;	return n;}#endif /* USE_FUNC_TD_LST_MTX */#ifdef USE_FUNC_TD_REF_MTX/* * Refer mutex state */SYSCALL ER td_ref_mtx_impl( ID mtxid, TD_RMTX *pk_rmtx ){	MTXCB	*mtxcb;	ER	ercd = E_OK;	CHECK_MTXID(mtxid);	mtxcb = get_mtxcb(mtxid);	BEGIN_DISABLE_INTERRUPT;	if ( mtxcb->mtxid == 0 ) {		ercd = E_NOEXS;	} else {		pk_rmtx->exinf = mtxcb->exinf;		pk_rmtx->htsk = ( mtxcb->mtxtsk != NULL )?					mtxcb->mtxtsk->tskid: 0;		pk_rmtx->wtsk = knl_wait_tskid(&mtxcb->wait_queue);	}	END_DISABLE_INTERRUPT;	return ercd;}#endif /* USE_FUNC_TD_REF_MTX */#ifdef USE_FUNC_TD_MTX_QUE/* * Refer mutex wait queue */SYSCALL INT td_mtx_que_impl( ID mtxid, ID list[], INT nent ){	MTXCB	*mtxcb;	QUEUE	*q;	ER	ercd = E_OK;	CHECK_MTXID(mtxid);	mtxcb = get_mtxcb(mtxid);	BEGIN_DISABLE_INTERRUPT;	if ( mtxcb->mtxid == 0 ) {		ercd = E_NOEXS;	} else {		INT n = 0;		for ( q = mtxcb->wait_queue.next; q != &mtxcb->wait_queue; q = q->next ) {			if ( n++ < nent ) {				*list++ = ((TCB*)q)->tskid;			}		}		ercd = n;	}	END_DISABLE_INTERRUPT;	return ercd;}#endif /* USE_FUNC_TD_MTX_QUE */#endif /* USE_DBGSPT */#endif /* CFN_MAX_MTXID */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -