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

📄 sem.c

📁 rtai-3.1-test3的源代码(Real-Time Application Interface )
💻 C
📖 第 1 页 / 共 4 页
字号:
/**  * @file * Semaphore functions. * @author Paolo Mantegazza * * @note Copyright (C) 1999-2003 Paolo Mantegazza * <mantegazza@aero.polimi.it> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * @ingroup sem *//** * @ingroup sched * @defgroup sem Semaphore functions * *@{*/#include <rtai_schedcore.h>#include <rtai_sem.h>#include <rtai_rwl.h>#include <rtai_spl.h>MODULE_LICENSE("GPL");/* +++++++++++++++++++++ ALL SEMAPHORES TYPES SUPPORT +++++++++++++++++++++++ *//** * @anchor rt_typed_sem_init * @brief Initialize a specifically typed (counting, binary, resource) *	  semaphore * * rt_typed_sem_init initializes a semaphore @e sem of type @e type. A * semaphore can be used for communication and synchronization among * real time tasks. Negative value of a semaphore shows how many tasks * are blocked on the semaphore queue, waiting to be awaken by calls * to rt_sem_signal. * * @param sem must point to an allocated SEM structure. * * @param value is the initial value of the semaphore, always set to 1 *	  for a resource semaphore. * * @param type is the semaphore type and queuing policy. It can be an OR * a semaphore kind: CNT_SEM for counting semaphores, BIN_SEM for binary  * semaphores, RES_SEM for resource semaphores; and queuing policy: * FIFO_Q, PRIO_Q for a fifo and priority queueing respectively. * Resource semaphores will enforce a PRIO_Q policy anyhow. *  * Counting semaphores can register up to 0xFFFE events. Binary * semaphores do not count signalled events, their count will never * exceed 1 whatever number of events is signaled to them. Resource * semaphores are special binary semaphores suitable for managing * resources. The task that acquires a resource semaphore becomes its * owner, also called resource owner, since it is the only one capable * of manipulating the resource the semaphore is protecting. The owner * has its priority increased to that of any task blocking on a wait * to the semaphore. Such a feature, called priority inheritance, * ensures that a high priority task is never slaved to a lower * priority one, thus allowing to avoid any deadlock due to priority * inversion. Resource semaphores can be recursed, i.e. their task * owner is not blocked by nested waits placed on an owned * resource. The owner must insure that it will signal the semaphore, * in reversed order, as many times as he waited on it. Note that that * full priority inheritance is supported both for resource semaphores * and inter task messages, for a singly owned resource. Instead it * becomes an adaptive priority ceiling when a task owns multiple * resources, including messages sent to him. In such a case in fact * its priority is returned to its base one only when all such * resources are released and no message is waiting for being * received. This is a compromise design choice aimed at avoiding * extensive searches for the new priority to be inherited across * multiply owned resources and blocked tasks sending messages to * him. Such a solution will be implemented only if it proves * necessary. Note also that, to avoid @e deadlocks, a task owning a * resource semaphore cannot be suspended. Any @ref rt_task_suspend() * posed on it is just registered. An owner task will go into suspend * state only when it releases all the owned resources. * * @note RTAI counting semaphores assume that their counter will never *	 exceed 0xFFFF, such a number being used to signal returns in *	 error. Thus also the initial count value cannot be greater *	 than 0xFFFF. To be used only with RTAI24.x.xx (FIXME). */void rt_typed_sem_init(SEM *sem, int value, int type){	sem->magic = RT_SEM_MAGIC;	sem->count = value;	sem->qtype = type != RES_SEM && (type & FIFO_Q) ? 1 : 0;	type = (type & 3) - 2;	if ((sem->type = type) < 0 && value > 1) {		sem->count = 1;	} else if (type > 0) {		sem->type = sem->count = 1;	}	sem->queue.prev = &(sem->queue);	sem->queue.next = &(sem->queue);	sem->queue.task = sem->owndby = 0;}/** * @anchor rt_sem_init * @brief Initialize a counting semaphore. * * rt_sem_init initializes a counting fifo queueing semaphore @e sem. * * A semaphore can be used for communication and synchronization among * real time tasks. * * @param sem must point to an allocated @e SEM structure. * * @param value is the initial value of the semaphore. *  * Positive values of the semaphore variable show how many tasks can * do a @ref rt_sem_wait() call without blocking. Negative value of a * semaphore shows how many tasks are blocked on the semaphore queue, * waiting to be awaken by calls to @ref rt_sem_signal(). * * @note RTAI counting semaphores assume that their counter will never *	 exceed 0xFFFF, such a number being used to signal returns in *	 error. Thus also the initial count value cannot be greater *	 than 0xFFFF. *	 This is an old legacy function. RTAI 24.1.xx has also  *	 @ref rt_typed_sem_init(), allowing to *	 choose among counting, binary and resource *	 semaphores. Resource semaphores have priority inherithance.  */void rt_sem_init(SEM *sem, int value){	rt_typed_sem_init(sem, value, CNT_SEM);}/** * @anchor rt_sem_delete * @brief Delete a semaphore * * rt_sem_delete deletes a semaphore previously created with  * @ref rt_sem_init().  * * @param sem points to the structure used in the corresponding * call to rt_sem_init.  * * Any tasks blocked on this semaphore is returned in error and * allowed to run when semaphore is destroyed.  * * @return 0 is returned upon success. A negative value is returned on * failure as described below:  * - @b 0xFFFF: @e sem does not refer to a valid semaphore. * * @note In principle 0xFFFF could theoretically be a usable *	 semaphores events count, so it could be returned also under *	 normal circumstances. It is unlikely you are going to count *	 up to such number of events, in any case avoid counting up  *	 to 0xFFFF.  */int rt_sem_delete(SEM *sem){	unsigned long flags;	RT_TASK *task;	unsigned long schedmap;	QUEUE *q;	if (sem->magic != RT_SEM_MAGIC) {		return SEM_ERR;	}	schedmap = 0;	q = &(sem->queue);	flags = rt_global_save_flags_and_cli();	sem->magic = 0;	while ((q = q->next) != &(sem->queue) && (task = q->task)) {		rem_timed_task(task);		if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_SEMAPHORE | RT_SCHED_DELAYED)) == RT_SCHED_READY) {			enq_ready_task(task);			set_bit(task->runnable_on_cpus & 0x1F, &schedmap);		}	}	clear_bit(hard_cpu_id(), &schedmap);	if ((task = sem->owndby) && sem->type > 0) {		int sched;		if (task->owndres & SEMHLF) {			--task->owndres;		}		if (!task->owndres) {			sched = renq_ready_task(task, task->base_priority);		} else if (!(task->owndres & SEMHLF)) {			int priority;                        sched = renq_ready_task(task, task->base_priority > (priority = ((task->msg_queue.next)->task)->priority) ? priority : task->base_priority);		} else {			sched = 0;		}		if (task->suspdepth) {			if (task->suspdepth > 0) {				task->state |= RT_SCHED_SUSPENDED;				rem_ready_task(task);				sched = 1;			} else {				rt_task_delete(task);			}		}		if (sched) {			if (schedmap) {				RT_SCHEDULE_MAP_BOTH(schedmap);			} else {				rt_schedule();			}		}	} else {		RT_SCHEDULE_MAP(schedmap);	}	rt_global_restore_flags(flags);	return 0;}int rt_sem_count(SEM *sem){	return sem->count;}/** * @anchor rt_sem_signal * @brief Signaling a semaphore. * * rt_sem_signal signals an event to a semaphore. It is typically * called when the task leaves a critical region. The semaphore value * is incremented and tested. If the value is not positive, the first * task in semaphore's waiting queue is allowed to run.  rt_sem_signal * never blocks the caller task. * * @param sem points to the structure used in the call to @ref * rt_sem_init(). *  * @return 0 is returned upon success. A negative value is returned on * failure as described below:  * - @b 0xFFFF: @e sem does not refer to a valid semaphore. * * @note In principle 0xFFFF could theoretically be a usable *	 semaphores events count, so it could be returned also under *	 normal circumstances. It is unlikely you are going to count *	 up to such number of events, in any case avoid counting up to * 	 0xFFFF. *	 See @ref rt_sem_wait() notes for some curiosities. */int rt_sem_signal(SEM *sem){	unsigned long flags;	RT_TASK *task;	int tosched;	if (sem->magic != RT_SEM_MAGIC) {		return SEM_ERR;	}	flags = rt_global_save_flags_and_cli();	if (sem->type) {		if (sem->type > 1) {			sem->type--;			rt_global_restore_flags(flags);			return 0;		}		if (++sem->count > 1) {			sem->count = 1;		}	} else {		sem->count++;	}	if ((task = (sem->queue.next)->task)) {		dequeue_blocked(task);		rem_timed_task(task);		if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_SEMAPHORE | RT_SCHED_DELAYED)) == RT_SCHED_READY) {			enq_ready_task(task);			if (sem->type <= 0) {				RT_SCHEDULE(task, hard_cpu_id());				rt_global_restore_flags(flags);				return 0;			}			tosched = 1;			goto res;		}	}	tosched = 0;res:	if (sem->type > 0) {		DECLARE_RT_CURRENT;		int sched;		ASSIGN_RT_CURRENT;		sem->owndby = 0;		if (rt_current->owndres & SEMHLF) {			--rt_current->owndres;		}		if (!rt_current->owndres) {			sched = renq_current(rt_current, rt_current->base_priority);		} else if (!(rt_current->owndres & SEMHLF)) {			int priority;			sched = renq_current(rt_current, rt_current->base_priority > (priority = ((rt_current->msg_queue.next)->task)->priority) ? priority : rt_current->base_priority);		} else {			sched = 0;		}		if (rt_current->suspdepth) {			if (rt_current->suspdepth > 0) {				rt_current->state |= RT_SCHED_SUSPENDED;				rem_ready_current(rt_current);                        	sched = 1;			} else {				rt_task_delete(rt_current);			}		}		if (sched) {			if (tosched) {				RT_SCHEDULE_BOTH(task, cpuid);			} else {				rt_schedule();			}		} else if (tosched) {			RT_SCHEDULE(task, cpuid);		}	}	rt_global_restore_flags(flags);	return 0;}/** * @anchor rt_sem_broadcast * @brief Signaling a semaphore. * * rt_sem_broadcast signals an event to a semaphore that unblocks all tasks * waiting on it. It is used as a support for RTAI proper conditional  * variables but can be of help in many other instances. After the broadcast * the semaphore counts is set to zero, thus all tasks waiting on it will * blocked. * * @param sem points to the structure used in the call to @ref * rt_sem_init(). *  * @returns 0 always. */int rt_sem_broadcast(SEM *sem){	unsigned long flags, schedmap;	RT_TASK *task;	QUEUE *q;	if (sem->magic != RT_SEM_MAGIC) {		return SEM_ERR;	}	schedmap = 0;	q = &(sem->queue);	flags = rt_global_save_flags_and_cli();	while ((q = q->next) != &(sem->queue)) {		dequeue_blocked(task = q->task);		rem_timed_task(task);		if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_SEMAPHORE | RT_SCHED_DELAYED)) == RT_SCHED_READY) {			enq_ready_task(task);			set_bit(task->runnable_on_cpus & 0x1F, &schedmap);		}		flags = rt_global_save_flags_and_cli();		rt_global_restore_flags(flags);	}	sem->count = 0;	if (schedmap) {		if (test_and_clear_bit(hard_cpu_id(), &schedmap)) {			RT_SCHEDULE_MAP_BOTH(schedmap);		} else {			RT_SCHEDULE_MAP(schedmap);		}	}	rt_global_restore_flags(flags);	return 0;}/** * @anchor rt_sem_wait * @brief Take a semaphore. * * rt_sem_wait waits for a event to be signaled to a semaphore. It is * typically called when a task enters a critical region. The * semaphore value is decremented and tested. If it is still * non-negative rt_sem_wait returns immediately. Otherwise the caller * task is blocked and queued up. Queuing may happen in priority order * or on FIFO base. This is determined by the compile time option @e * SEM_PRIORD. In this case rt_sem_wait returns if: *	       - The caller task is in the first place of the waiting *		 queue and another task issues a @ref rt_sem_signal() *		 call; *	       - An error occurs (e.g. the semaphore is destroyed); * * @param sem points to the structure used in the call to @ref *	  rt_sem_init(). * * @return the number of events already signaled upon success. * A special value" as described below in case of a failure : * - @b 0xFFFF: @e sem does not refer to a valid semaphore. * * @note In principle 0xFFFF could theoretically be a usable *	 semaphores events count, so it could be returned also under *	 normal circumstances. It is unlikely you are going to count *	 up to such number of events, in any case avoid counting up to *	 0xFFFF.<br> *	 Just for curiosity: the original Dijkstra notation for *	 rt_sem_wait was a "P" operation, and rt_sem_signal was a "V" *	 operation. The name for P comes from the Dutch "prolagen", a *	 combination of "proberen" (to probe) and "verlagen" (to *	 decrement). Also from the word "passeren" (to pass).<br> *	 The name for V comes from the Dutch "verhogen" (to increase) *	 or "vrygeven" (to release).  (Source: Daniel Tabak - *	 Multiprocessors, Prentice Hall, 1990).<br> *	 It should be also remarked that real time programming *	 practitioners were using semaphores a long time before *	 Dijkstra formalized P and V. "In Italian semaforo" means a *	 traffic light, so that semaphores have an intuitive appeal * 	 and their use and meaning is easily understood. */int rt_sem_wait(SEM *sem){	RT_TASK *rt_current;	unsigned long flags;	int count;	if (sem->magic != RT_SEM_MAGIC) {		return SEM_ERR;	}	flags = rt_global_save_flags_and_cli();	rt_current = RT_CURRENT;	if ((count = sem->count) <= 0) {		unsigned long schedmap;		if (sem->type > 0) {			if (sem->owndby == rt_current) {				sem->type++;				rt_global_restore_flags(flags);				return count;			}			schedmap = pass_prio(sem->owndby, rt_current);		} else {			schedmap = 0;		}

⌨️ 快捷键说明

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