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

📄 mutex.c

📁 日本著名的的嵌入式实时操作系统T-Kernel的源码及用户手册。
💻 C
字号:
/* *---------------------------------------------------------------------- *    T-Kernel * *    Copyright (C) 2004 by Ken Sakamura. All rights reserved. *    T-Kernel is distributed under the T-License. *---------------------------------------------------------------------- * *    Version:   1.01.00 *    Released by T-Engine Forum(http://www.t-engine.org) at 2004/6/28. * *---------------------------------------------------------------------- *//* *	mutex.c (T-Kernel/OS) *	Mutex */#include "kernel.h"#include "task.h"#include "wait.h"#include "check.h"#ifdef NUM_MTXIDEXPORT ID	max_mtxid;	/* Maximum mutex ID */#ifndef __mtxcb__#define __mtxcb__typedef struct mutex_control_block	MTXCB;#endif/* * Mutex control block */struct mutex_control_block {	QUEUE	wait_queue;	/* Mutex wait queue */	ID	mtxid;		/* Mutex ID */	VP	exinf;		/* Extended information */	ATR	mtxatr;		/* Mutex attribute */	UB	ceilpri;	/* Highest priority limit of mutex */	TCB	*mtxtsk;	/* Mutex get task */	MTXCB	*mtxlist;	/* Mutex get list */#if USE_OBJECT_NAME	UB	name[OBJECT_NAME_LENGTH];	/* name */#endif};LOCAL MTXCB	*mtxcb_table;	/* Mutex control block */LOCAL QUEUE	free_mtxcb;	/* FreeQue */#define get_mtxcb(id)	( &mtxcb_table[INDEX_MTX(id)] )/* * Initialization of mutex control block  */EXPORT ER mutex_initialize(void){	MTXCB	*mtxcb, *end;	W	n;	/* Get system information */	n = _tk_get_cfn("TMaxMtxId", &max_mtxid, 1);	if ( n < 1 || NUM_MTXID < 1 ) return E_SYS;	/* Create mutex control block */	mtxcb_table = Imalloc(NUM_MTXID * sizeof(MTXCB));	if ( mtxcb_table == NULL ) return E_NOMEM;	/* Register all control blocks onto FeeQue*/	QueInit(&free_mtxcb);	end = mtxcb_table + NUM_MTXID;	for( mtxcb = mtxcb_table; mtxcb < end; mtxcb++ ) {		mtxcb->mtxid = 0;		QueInsert(&mtxcb->wait_queue, &free_mtxcb);	}	return E_OK;}/* * If there is a mutex 'mtxcb' with the task of lock wait, it is TRUE */#define mtx_waited(mtxcb)	( !isQueEmpty(&(mtxcb)->wait_queue) )/* * Return the highest priority in the task of lock wait at mutex 'mtxcb' */#define	mtx_head_pri(mtxcb)	( ((TCB*)(mtxcb)->wait_queue.next)->priority )/* * 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. */LOCAL void 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;		}		if ( newpri > pri ) newpri = pri;		prev = &mtxcb->mtxlist;	}	if ( newpri != tcb->priority ) {		/* Change priority of lock get task */		change_task_priority(tcb, newpri);	}}/* * Reset priority of lock get task (For TA_INHERIT only) */#define reset_priority(tcb)	release_mutex(tcb, NULL)/* * Free mutex when task is terminated *	Free all mutexes which the task holds. *	Do not need to handle mutex list and priority of terminatined task. *	 */EXPORT void 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*/			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 */					change_task_priority(next_tcb,							mtxcb->ceilpri);				}			}		} else {			/* No wait task*/			mtxcb->mtxtsk = NULL;		}	}}/* * 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 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;		}		if ( pri < hi_pri ) hi_pri = pri;	}	if ( priority < low_pri ) return E_ILUSE;	return hi_pri;}/* * 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);	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 */			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 wspec_mtx_tfifo   = { TTW_MTX, NULL, NULL };LOCAL WSPEC wspec_mtx_tpri    = { TTW_MTX, mtx_chg_pri, NULL };LOCAL WSPEC wspec_mtx_inherit = { TTW_MTX, mtx_chg_pri, mtx_rel_wai };/* * Create mutex */SYSCALL ID _tk_cre_mtx( T_CMTX *pk_cmtx ){	const ATR VALID_MTXATR = {		 TA_CEILING		|TA_NODISWAI#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(&free_mtxcb);	if ( mtxcb == NULL ) {		ercd = E_LIMIT;	} else {		mtxid = ID_MTX(mtxcb - 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(mtxcb->name, pk_cmtx->dsname,				OBJECT_NAME_LENGTH);		}#endif		ercd = mtxid;	}	END_CRITICAL_SECTION;	return ercd;}/* * Delete mutex */SYSCALL ER _tk_del_mtx( 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 ) {			release_mutex(mtxcb->mtxtsk, mtxcb);		}		/* Free wait state of task (E_DLT) */		wait_delete(&mtxcb->wait_queue);		/* Return to FreeQue */		QueInsert(&mtxcb->wait_queue, &free_mtxcb);		mtxcb->mtxid = 0;	}	END_CRITICAL_SECTION;	return ercd;}/* * Lock mutex */SYSCALL ER _tk_loc_mtx( 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 == ctxtsk ) {		ercd = E_ILUSE;  /* Multiplexed lock */		goto error_exit;	}	mtxatr = mtxcb->mtxatr & TA_CEILING;	if ( mtxatr == TA_CEILING ) {		if ( ctxtsk->bpriority < mtxcb->ceilpri ) {			/* Violation of highest priority limit */			ercd = E_ILUSE;			goto error_exit;		}	}	/* Check wait disable */	if ( is_diswai((GCB*)mtxcb, ctxtsk, TTW_MTX) ) {		ercd = E_DISWAI;		goto error_exit;	}	mtxtsk = mtxcb->mtxtsk;	if ( mtxtsk == NULL ) {		/* Get lock */		mtxcb->mtxtsk = ctxtsk;		mtxcb->mtxlist = ctxtsk->mtxlist;		ctxtsk->mtxlist = mtxcb;		if ( mtxatr == TA_CEILING ) {			if ( ctxtsk->priority > mtxcb->ceilpri ) {				/* Raise its own task to the highest				   priority limit */				change_task_priority(ctxtsk, mtxcb->ceilpri);			}		}	} else {		ercd = E_TMOUT;		if ( tmout == TMO_POL ) goto error_exit;		if ( mtxatr == TA_INHERIT ) {			if ( mtxtsk->priority > ctxtsk->priority ) {				/* Raise the priority of task during				   locking to the same priority as its				   own task */				change_task_priority(mtxtsk, ctxtsk->priority);			}		}		/* Ready for wait */		ctxtsk->wspec = ( mtxatr == TA_TFIFO   )? &wspec_mtx_tfifo:				( mtxatr == TA_INHERIT )? &wspec_mtx_inherit:							  &wspec_mtx_tpri;		ctxtsk->wercd = &ercd;		ctxtsk->wid = mtxcb->mtxid;		make_wait(tmout, mtxcb->mtxatr);		if ( mtxatr == TA_TFIFO ) {			QueInsert(&ctxtsk->tskque, &mtxcb->wait_queue);		} else {			queue_insert_tpri(ctxtsk, &mtxcb->wait_queue);		}	}    error_exit:	END_CRITICAL_SECTION;	return ercd;}/* * Unlock mutex */SYSCALL ER _tk_unl_mtx( 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 != 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. */	release_mutex(ctxtsk, mtxcb);	if ( mtx_waited(mtxcb) ) {		tcb = (TCB*)mtxcb->wait_queue.next;		/* Release wait */		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 */				change_task_priority(tcb, mtxcb->ceilpri);			}		}	} else {		/* No wait task*/		mtxcb->mtxtsk = NULL;	}    error_exit:	END_CRITICAL_SECTION;	return ercd;}/* * Refer mutex state */SYSCALL ER _tk_ref_mtx( 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 = wait_tskid(&mtxcb->wait_queue);	}	END_CRITICAL_SECTION;	return ercd;}/* ------------------------------------------------------------------------ *//* *	Debugger support function */#if USE_DBGSPT/* * Get object name from control block */#if USE_OBJECT_NAMEEXPORT ER 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 *//* * Refer mutex usage state */SYSCALL INT _td_lst_mtx( ID list[], INT nent ){	MTXCB	*mtxcb, *end;	INT	n = 0;	BEGIN_DISABLE_INTERRUPT;	end = mtxcb_table + NUM_MTXID;	for ( mtxcb = mtxcb_table; mtxcb < end; mtxcb++ ) {		if ( mtxcb->mtxid == 0 ) continue;		if ( n++ < nent ) {			*list++ = mtxcb->mtxid;		}	}	END_DISABLE_INTERRUPT;	return n;}/* * Refer mutex state */SYSCALL ER _td_ref_mtx( 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 = wait_tskid(&mtxcb->wait_queue);	}	END_DISABLE_INTERRUPT;	return ercd;}/* * Refer mutex wait queue */SYSCALL INT _td_mtx_que( 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_DBGSPT */#endif /* NUM_MTXID */

⌨️ 快捷键说明

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