📄 semaphore.c
字号:
/* semaphore.c: FR-V semaphores * * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * - Derived from lib/rwsem-spinlock.c * * 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. */#include <linux/config.h>#include <linux/sched.h>#include <linux/module.h>#include <asm/semaphore.h>struct sem_waiter { struct list_head list; struct task_struct *task;};#if SEMAPHORE_DEBUGvoid semtrace(struct semaphore *sem, const char *str){ if (sem->debug) printk("[%d] %s({%d,%d})\n", current->pid, str, sem->counter, list_empty(&sem->wait_list) ? 0 : 1);}#else#define semtrace(SEM,STR) do { } while(0)#endif/* * wait for a token to be granted from a semaphore * - entered with lock held and interrupts disabled */void __down(struct semaphore *sem, unsigned long flags){ struct task_struct *tsk = current; struct sem_waiter waiter; semtrace(sem, "Entering __down"); /* set up my own style of waitqueue */ waiter.task = tsk; get_task_struct(tsk); list_add_tail(&waiter.list, &sem->wait_list); /* we don't need to touch the semaphore struct anymore */ spin_unlock_irqrestore(&sem->wait_lock, flags); /* wait to be given the semaphore */ set_task_state(tsk, TASK_UNINTERRUPTIBLE); for (;;) { if (list_empty(&waiter.list)) break; schedule(); set_task_state(tsk, TASK_UNINTERRUPTIBLE); } tsk->state = TASK_RUNNING; semtrace(sem, "Leaving __down");}EXPORT_SYMBOL(__down);/* * interruptibly wait for a token to be granted from a semaphore * - entered with lock held and interrupts disabled */int __down_interruptible(struct semaphore *sem, unsigned long flags){ struct task_struct *tsk = current; struct sem_waiter waiter; int ret; semtrace(sem,"Entering __down_interruptible"); /* set up my own style of waitqueue */ waiter.task = tsk; get_task_struct(tsk); list_add_tail(&waiter.list, &sem->wait_list); /* we don't need to touch the semaphore struct anymore */ set_task_state(tsk, TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&sem->wait_lock, flags); /* wait to be given the semaphore */ ret = 0; for (;;) { if (list_empty(&waiter.list)) break; if (unlikely(signal_pending(current))) goto interrupted; schedule(); set_task_state(tsk, TASK_INTERRUPTIBLE); } out: tsk->state = TASK_RUNNING; semtrace(sem, "Leaving __down_interruptible"); return ret; interrupted: spin_lock_irqsave(&sem->wait_lock, flags); if (!list_empty(&waiter.list)) { list_del(&waiter.list); ret = -EINTR; } spin_unlock_irqrestore(&sem->wait_lock, flags); if (ret == -EINTR) put_task_struct(current); goto out;}EXPORT_SYMBOL(__down_interruptible);/* * release a single token back to a semaphore * - entered with lock held and interrupts disabled */void __up(struct semaphore *sem){ struct task_struct *tsk; struct sem_waiter *waiter; semtrace(sem,"Entering __up"); /* grant the token to the process at the front of the queue */ waiter = list_entry(sem->wait_list.next, struct sem_waiter, list); /* We must be careful not to touch 'waiter' after we set ->task = NULL. * It is an allocated on the waiter's stack and may become invalid at * any time after that point (due to a wakeup from another source). */ list_del_init(&waiter->list); tsk = waiter->task; mb(); waiter->task = NULL; wake_up_process(tsk); put_task_struct(tsk); semtrace(sem,"Leaving __up");}EXPORT_SYMBOL(__up);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -