关于信号量的获取
各个OS中都有信号量的获取函数,在VxWorks中是类似semTake的一组函数:semBTake,semMTake,semCTake,semRTake,semWTake. 这些函数分别对应于
二进制信号量 The fastest, most general-purpose semaphore,
互斥信号量 optimized for problems inherent in mutual exclusion: priority inversion, deletion safety, and recursion.,
计数信号量 Optimized for guarding multiple instances of a resource.,
读写信号量 particularly useful for SMP systems.
semTake根据信号量的类型,调用相应的take函数。
VxWorks除了自身的信号量外,为了提高程序的移植性,还提供了POSIX的信号量
sem_init( ) Initializes an unnamed semaphore.
sem_destroy( ) Destroys an unnamed semaphore.
sem_open( ) Initializes/opens a named semaphore.
sem_close( ) Closes a named semaphore.
sem_unlink( ) Removes a named semaphore.
sem_wait( ) Lock a semaphore.
sem_trywait( ) Lock a semaphore only if it is not already locked.
sem_post( ) Unlock a semaphore.
sem_getvalue( ) Get the value of a semaphore.
sem_timedwait( ) Lock a semaphore with a timeout. The timeout is based on the CLOCK_REALTIME clock.
在VxWorks Kernel Programmer's Guide里,注明了两种信号量的差别:
The VxWorks semaphore mechanism is similar to that
specified by POSIX, except that VxWorks semaphores offer these additional
features:
■ priority inheritance
■ task-deletion safety
■ the ability for a single task to take a semaphore multiple times
■ ownership of mutual-exclusion semaphores
■ semaphore timeouts
■ queuing mechanism options
semBTake的单核版本实现,就是
1,锁中断
2,检查sem标志
3,如果 sem可用,则设置sem不可用,解锁中断返回OK
4,如果 是立刻返回 则 解锁中断返回ERROR
5,解锁中断
6,把自身任务加到sem的pend队列里(windPendQPut)。
7,调用KERNEL_UNLOCK(==windExit)重新调度。
对SMP版本,和上面类似,注意两点:1,锁中断和up类似,只锁local CPU的中断,2检查设置标志时,使用原子操作,防止其他CPU更改标志。
在这里,经常会遇到一个中断处理函数中不能调用导致block函数的问题。
风河的文档中是这么写的:
===
No Blocking Routines
Many VxWorks facilities are available to ISRs, but there are some important
limitations. These limitations stem from the fact that an ISR does not run in a
regular task context and has no task control block, so all ISRs share a single stack.
For this reason, the basic restriction on ISRs is that they must not invoke routines
that might cause the caller to block. For example, they must not try to take a
semaphore, because if the semaphore is unavailable, the kernel tries to switch the
caller to the pended state. However, ISRs can give semaphores, releasing any tasks
waiting on them.
Because the memory facilities malloc( ) and free( ) take a semaphore, they cannot
be called by ISRs, and neither can routines that make calls to malloc( ) and free( ).
For example, ISRs cannot call any creation or deletion routines.
ISRs also must not perform I/O through VxWorks drivers. Although there are no
inherent restrictions in the I/O system, most device drivers require a task context
because they might block the caller to wait for the device. An important exception
is the VxWorks pipe driver, which is designed to permit writes by ISRs. VxWorks
also provides several routines that can be called from an ISR to print messages to
the system console: logMsg( ), kprintf( ), and kputs( ).
===
那么为什么中断中不能调用semTake呢?
如果sem可用,那么semTake把sem设成不可用,就直接返回了。这时,不会引起block。所以系统能够正常工作。
如果sem不可用,那么这个问题实际上等价于为什么中断中不能调用windPengQPut?
因为这个函数会把当前任务(taskIdCurrent)的状态置成pend, 并把当前任务挂到信号量的pending队列里。
当在任务上下文执行semTake时,没有问题。当在中断上下文时,这个函数相当于把进中断前的任务(或者说被中断打断的任务)pend了。所以block的意思不是block中断,而是block任务。
这个倒霉的任务必须要等到信号量的释放函数才能继续执行。而semGive永远也等不到了,因为在中断中调用semTake,通常倒霉的coder是想保护一段代码,semGive在semTake的下面,中断处理函数在semTake的时候就被调度程序调度走了。
当中断前的任务是个很关键的任务是,系统就会崩溃。
最后,还有一个问题,什么时候sem可用,什么时候sem不可用?
如果在中断中使用的sem,同时也在某个任务中该sem被take,这时肯定该sem就不可用了。
如果这个sem只在这一个中断处理函数中使用,那么情形又如何呢?
这种情形下,要区分中断controller的驱动程序是否允许中断重入,如果不会引起中断重入,那么semTake总能take到sem,这样就不会引起系统block不会引起死机但是也毫无意义。因为对于使用sem进行互斥的情况,必然有两个可能同时执行地方使用semTake/semGive保护一段代码才有意义。
对于VxWorks的大部分中断controller驱动程序,当一个中断处理函数在执行时,该优先级的中断是关闭的,并且在中断处理函数执行完后,才会ack该中断,所以一般不会引起中断重入的问题。
阅读(3815) | 评论(0) | 转发(0) |