The basic idea of locking and unlocking is that when a process enters a critical section, it will hold a certain type of lock (Unix generally semaphore,linux is usually a semaphore and atomic weight or spinlock). When another process attempts to enter the critical section (lock) when the process does not release the lock, it is set to sleep and is placed in the process queue (a priority) that waits for the lock. When the lock is freed, that is, when the unlocking event occurs, the kernel looks for a process from the process priority queue waiting for the lock and put it in a ready state, waiting for dispatch (schedule).
In System V, you wait for an event to be called sleep (sleeping on the An event), so the following will unify the use of Morpheus. Waiting for an event can also become a wait for a lock. (Note: The sleep in this article differs from the sleep () system call)
The implementation of the system maps a set of events to a set of kernel virtual addresses (locks), and the event does not discriminate between how many processes are waiting. This means two irregular things:
When an event occurs, a set of processes waiting for the event are awakened (rather than just waking a process), and the state is set to Ready (Ready-to-run). At this time, the kernel chooses (schedule) a process to execute, because the System V kernel is not preemptive (the Linux kernel can preempt), so that other processes will remain in the ready state for scheduling, or sleep again (because the lock is likely to be held by the execution process, The execution process sleeps because it waits for other events to occur, or other processes are preempted in the user state.
Two, multiple events are mapped to the same address (lock). Suppose the event E1 and E2 are mapped to the same address (lock) addr, there is a set of processes waiting for E1, a set of processes waiting for E2, they wait for different events, but the corresponding locks are the same. If E2 occurs, all processes waiting for E2 are awakened into a ready state, and since E1 does not occur, the lock addr is not released and all awakened processes return to sleep. It seems that an event that addresses an address can increase efficiency, but in fact because System V is a non preemptive kernel, and this many-to-many mapping is very small, plus the running process will soon release resources (before other processes are scheduled), this mapping does not result in significant performance degradation.
The following is a brief description of the sleep and wakeup algorithms.
Pseudo code
Sleep (Address (event), priority)
Return value: A process can capture a signal that results in a return of 1, which returns a longjmp algorithm when a signal that the process cannot capture occurs, or 0.
{
提高处理器执行等级以禁用所有中断;//避免竞态条件
将进程的状态设置为睡眠;
根据事件将进程放入睡眠哈希队列;//一般来说每个事件都有一个等待队列
将睡眠地址(事件)及输入的优先级保存到进程表中;
if (该等待是不可中断的等待)
//一般有两种睡眠状态:可中断的和不可中断的。不可中断的睡眠是指进程除了等待的事件外,
//不会被其他任何事件(如信号)中断睡眠状态,该情况不太常用。
{
上下文切换;//此处该进程执行上下文被保存起来,内核转而执行其他进程
//在别处进行了上下文切换,内核选择该上下文进行执行,此时该进程被唤醒
恢复处理器等级来允许中断;
返回0;
}
// 被信号中断的睡眠
if (没有未递送的信号)
{
上下文切换;
if (没有未递送的信号)
{
恢复处理器等级来允许中断;
返回0;
}
}
//有未递送的信号
若进程还在等待哈希队列中,将其从该队列移出;
恢复处理器等级来允许中断;
if(进程捕获该信号)
返回1;
执行longjmp算法;//这一段我也不明白
}
void Wakeup (Address (event))
{
禁用所有的中断;
根据地址(事件)查找睡眠进程队列;
for(每个在该事件上睡眠的进程)
{
将该进程从哈希队列中移出;
设置状态为就绪;
将该进程放入调度链表中;
清除进程表中的睡眠地址(事件);
if(进程不在内存中)
{
唤醒swapper进程;
}
else if(唤醒的进程更适合运行)
{
设置调度标志;
}
}
恢复中断;
}
After the wakeup call, the awakened process does not run immediately, but rather it is ready to run until the next time the process is scheduled to run (or it may not run).