From: monstr@monstr.eu
To: monstr@monstr.eu
Cc: linux-kernel@vger.kernel.org, stephen.neuendorffer@xilinx.com,
john.williams@petalogix.com, microblaze-uclinux@itee.uq.edu.au
Subject: [PATCH 05/52] [microblaze] Support for semaphores
Date: Thu, 24 Jan 2008 16:03:30 +0100 [thread overview]
Message-ID: <e83ac9f205e3ef0524ded397faf91a7a0750100c.1201107832.git.monstr@monstr.eu> (raw)
In-Reply-To: <c4d02deb7e0a9a243a961bfe066e5d05e72a836e.1201107832.git.monstr@monstr.eu>
In-Reply-To: <8051f6df628e1ff896ec7d580b613da50f718fb4.1201107832.git.monstr@monstr.eu>
From: Michal Simek <monstr@monstr.eu>
Signed-off-by: Michal Simek <monstr@monstr.eu>
---
arch/microblaze/kernel/semaphore.c | 222 ++++++++++++++++++++++++++++++++++++
include/asm-microblaze/semaphore.h | 100 ++++++++++++++++
2 files changed, 322 insertions(+), 0 deletions(-)
create mode 100644 arch/microblaze/kernel/semaphore.c
create mode 100644 include/asm-microblaze/semaphore.h
diff --git a/arch/microblaze/kernel/semaphore.c b/arch/microblaze/kernel/semaphore.c
new file mode 100644
index 0000000..360fc7b
--- /dev/null
+++ b/arch/microblaze/kernel/semaphore.c
@@ -0,0 +1,222 @@
+/*
+ * arch/microblaze/kernel/semaphore.c
+ *
+ * Generic semaphore code. Buyer beware. Do your own specific changes
+ * in <asm/semaphore-helper.h>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ */
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+#include <asm/errno.h>
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+
+static inline void wake_one_more(struct semaphore *sem)
+{
+ atomic_inc((atomic_t *)&sem->sleepers);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ if (sem->sleepers > 0) {
+ sem->sleepers--;
+ ret = 1;
+ }
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ * 1 got the lock
+ * 0 go to sleep
+ * -EINTR interrupted
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+ struct task_struct *tsk) {
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ if (sem->sleepers > 0) {
+ sem->sleepers--;
+ ret = 1;
+ } else if (signal_pending(tsk)) {
+ atomic_inc(&sem->count);
+ ret = -EINTR;
+ }
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ * 1 failed to lock
+ * 0 got the lock
+ *
+ * We must undo the sem->count down_trylock() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+ unsigned long flags;
+ int ret = 1;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ if (sem->sleepers <= 0)
+ atomic_inc(&sem->count);
+ else {
+ sem->sleepers--;
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+spinlock_t semaphore_wake_lock;
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit. ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore. The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+
+void __up(struct semaphore *sem)
+{
+ wake_one_more(sem);
+ wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function. Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible. This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return. If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+#define DOWN_VAR \
+ struct task_struct *tsk = current; \
+ wait_queue_t wait; \
+ init_waitqueue_entry(&wait, tsk);
+
+#define DOWN_HEAD(task_state) \
+ \
+ \
+ tsk->state = (task_state); \
+ add_wait_queue(&sem->wait, &wait); \
+ \
+ /* \
+ * Ok, we're set up. sem->count is known to be less than zero \
+ * so we must wait. \
+ * \
+ * We can let go the lock for purposes of waiting. \
+ * We re-acquire it after awaking so as to protect \
+ * all semaphore operations. \
+ * \
+ * If "up()" is called before we call waking_non_zero() then \
+ * we will catch it right away. If it is called later then \
+ * we will have to go through a wakeup cycle to catch it. \
+ * \
+ * Multiple waiters contend for the semaphore lock to see \
+ * who gets to gate through and who has to wait some more. \
+ */ \
+ for (;;) {
+
+#define DOWN_TAIL(task_state) \
+ tsk->state = (task_state); \
+ } \
+ tsk->state = TASK_RUNNING; \
+ remove_wait_queue(&sem->wait, &wait);
+
+void __sched __down(struct semaphore *sem) {
+ DOWN_VAR
+ DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+ if (waking_non_zero(sem))
+ break;
+ schedule();
+ DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __sched __down_interruptible(struct semaphore *sem) {
+ int ret = 0;
+ DOWN_VAR
+ DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+ ret = waking_non_zero_interruptible(sem, tsk);
+ if (ret) {
+ if (ret == 1)
+ /* ret != 0 only if we get interrupted -arca */
+ ret = 0;
+ break;
+ }
+ schedule();
+ DOWN_TAIL(TASK_INTERRUPTIBLE)
+ return ret;
+}
+
+int __down_trylock(struct semaphore *sem)
+{
+ return waking_non_zero_trylock(sem);
+}
diff --git a/include/asm-microblaze/semaphore.h b/include/asm-microblaze/semaphore.h
new file mode 100644
index 0000000..f59aae6
--- /dev/null
+++ b/include/asm-microblaze/semaphore.h
@@ -0,0 +1,100 @@
+/*
+ * include/asm-microblaze/semaphore.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ */
+
+#ifndef _ASM_SEMAPHORE_H
+#define _ASM_SEMAPHORE_H
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
+
+struct semaphore {
+ atomic_t count;
+ int sleepers;
+ wait_queue_head_t wait;
+};
+
+#define __SEMAPHORE_INITIALIZER(name,n) \
+{ \
+ .count = ATOMIC_INIT(n), \
+ .sleepers = 0, \
+ .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+}
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+ struct semaphore name = __SEMAPHORE_INITIALIZER(name, count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name, 0)
+
+static inline void sema_init(struct semaphore *sem, int val)
+{
+ atomic_set(&sem->count, val);
+ sem->sleepers = 0;
+ init_waitqueue_head(&sem->wait);
+}
+
+static inline void init_MUTEX(struct semaphore *sem)
+{
+ sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED(struct semaphore *sem)
+{
+ sema_init(sem, 0);
+}
+
+asmlinkage void __down(struct semaphore *sem);
+asmlinkage int __down_interruptible(struct semaphore *sem);
+asmlinkage int __down_trylock(struct semaphore *sem);
+asmlinkage void __up(struct semaphore *sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+static inline void down(struct semaphore *sem)
+{
+ might_sleep();
+
+ if (atomic_sub_return(1, &sem->count) < 0)
+ __down(sem);
+}
+
+static inline int down_interruptible(struct semaphore *sem)
+{
+ int ret = 0;
+
+ might_sleep();
+
+ if (atomic_sub_return(1, &sem->count) < 0)
+ ret = __down_interruptible(sem);
+ return ret;
+}
+
+static inline int down_trylock(struct semaphore *sem)
+{
+ int ret = 0;
+
+ if (atomic_sub_return(1, &sem->count) < 0)
+ ret = __down_trylock(sem);
+ return ret;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ */
+static inline void up(struct semaphore *sem)
+{
+ if (atomic_add_return(1, &sem->count) <= 0)
+ __up(sem);
+}
+
+#endif /* _ASM_SEMAPHORE_H */
--
1.5.4.rc4.14.g6fc74
next prev parent reply other threads:[~2008-01-26 16:07 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-01-24 15:02 Microblaze init port monstr
2008-01-24 15:05 ` [PATCH 01/52] [microblaze] Kconfig patches monstr
2008-01-24 15:02 ` [PATCH 10/52] [microblaze] Generic dts file for platforms monstr
2008-01-24 15:02 ` [PATCH 11/52] [microblaze] kernel modules support monstr
2008-01-26 16:27 ` Jan Engelhardt
2008-01-24 15:02 ` [PATCH 12/52] [microblaze] lmb support monstr
2008-01-27 12:51 ` Jan Engelhardt
2008-01-24 15:02 ` [PATCH 13/52] [microblaze] PVR support, cpuinfo support monstr
2008-01-24 15:02 ` [PATCH 14/52] [microblaze] defconfig file monstr
2008-01-24 15:02 ` [PATCH 15/52] [microblaze] assembler files head.S, entry.S, monstr
2008-01-24 15:02 ` [PATCH 16/52] [microblaze] supported function for memory - kernel/lib monstr
2008-01-29 21:26 ` Jan Engelhardt
2008-01-24 15:02 ` [PATCH 17/52] [microblaze] checksum support monstr
2008-01-27 11:57 ` Geert Uytterhoeven
2008-01-27 13:41 ` Michal Simek
2008-01-27 15:12 ` Geert Uytterhoeven
2008-01-29 21:30 ` Jan Engelhardt
2008-01-24 15:02 ` [PATCH 18/52] [microblaze] early_printk support monstr
2008-01-24 15:02 ` [PATCH 19/52] [microblaze] uaccess files monstr
2008-01-24 15:02 ` [PATCH 20/52] [microblaze] heartbeat file monstr
2008-01-24 15:02 ` [PATCH 21/52] [microblaze] setup.c - system setting monstr
2008-01-24 15:02 ` [PATCH 22/52] [microblaze] asm-offsets monstr
2008-01-24 15:02 ` [PATCH 23/52] [microblaze] process and init task function monstr
2008-01-24 15:02 ` [PATCH 24/52] [microblaze] time support monstr
[not found] ` <47BD86F3.9030400@petalogix.com>
[not found] ` <20080221163040.5E9FA6A0056@mail168-sin.bigfish.com>
2008-03-02 19:25 ` [microblaze-uclinux] " Michal Simek
2008-01-24 15:03 ` [PATCH 25/52] [microblaze] ptrace support monstr
2008-01-24 15:03 ` [PATCH 26/52] [microblaze] IPC support monstr
2008-01-24 15:03 ` [PATCH 27/52] [microblaze] traps support monstr
2008-01-24 15:03 ` [PATCH 28/52] [microblaze] support for a.out monstr
2008-01-24 15:03 ` [PATCH 29/52] [microblaze] memory inicialization, MMU, TLB monstr
2008-01-24 15:03 ` [PATCH 30/52] [microblaze] consistent allocation & page.h, monstr
2008-01-24 15:03 ` [PATCH 31/52] [microblaze] pci header files monstr
2008-01-24 15:03 ` [PATCH 32/52] [microblaze] includes SHM*, msgbuf monstr
2008-01-24 15:03 ` [PATCH 33/52] [microblaze] bug headers files monstr
2008-01-24 15:03 ` [PATCH 34/52] [microblaze] definitions of types monstr
2008-01-24 15:03 ` [PATCH 35/52] [microblaze] ioctl support monstr
2008-01-24 15:03 ` [PATCH 36/52] [microblaze] io.h IO operations monstr
2008-01-24 15:03 ` [PATCH 37/52] [microblaze] headers for executables format FLAT, ELF monstr
2008-01-24 15:03 ` [PATCH 38/52] [microblaze] dma support monstr
2008-01-24 15:03 ` [PATCH 39/52] [microblaze] headers for irq monstr
2008-01-24 15:03 ` [PATCH 40/52] [microblaze] atomic.h bitops.h byteorder.h monstr
2008-01-24 15:03 ` [PATCH 41/52] [microblaze] headers pgalloc.h pgtable.h monstr
2008-01-24 15:03 ` [PATCH 42/52] [microblaze] system.h pvr.h processor.h monstr
2008-01-24 15:03 ` [PATCH 43/52] [microblaze] clinkage.h linkage.h sections.h kmap_types.h monstr
2008-01-24 15:03 ` [PATCH 44/52] [microblaze] stats headers monstr
2008-01-24 15:03 ` [PATCH 45/52] [microblaze] termbits.h termios.h monstr
2008-01-24 15:03 ` [PATCH 46/52] [microblaze] sigcontext.h siginfo.h monstr
2008-01-24 15:03 ` [PATCH 47/52] [microblaze] headers simple files monstr
2008-01-24 15:03 ` [PATCH 48/52] [microblaze] headers files entry.h current.h mman.h registers.h sembuf.h monstr
2008-01-24 15:03 ` [PATCH 49/52] [microblaze] device.h param.h topology.h monstr
2008-01-24 15:03 ` [PATCH 50/52] [microblaze] pool.h socket.h monstr
2008-01-24 15:03 ` [PATCH 51/52] [microblaze] fcntl.h sockios.h ucontext.h unistd.h monstr
2008-01-24 15:03 ` [PATCH 52/52] [microblaze] setup.h string.h thread_info.h monstr
2008-01-24 15:03 ` [PATCH 03/52] [microblaze] Cpuinfo handling monstr
2008-01-27 12:55 ` Jan Engelhardt
2008-01-24 15:03 ` [PATCH 04/52] [microblaze] Open firmware files monstr
2008-01-24 15:03 ` monstr [this message]
2008-01-24 15:03 ` [PATCH 06/52] [microblaze] exception handling monstr
2008-01-24 15:03 ` [PATCH 07/52] [microblaze] Signal support monstr
2008-01-24 15:03 ` [PATCH 08/52] [microblaze] Interrupt handling, timer support, supported function monstr
2008-01-24 15:03 ` [PATCH 09/52] [microblaze] cache support monstr
2008-01-24 15:05 ` [PATCH 02/52] [microblaze] Makefiles for Microblaze cpu monstr
2008-01-26 17:36 ` [PATCH 01/52] [microblaze] Kconfig patches Randy Dunlap
2008-01-27 10:39 ` Michal Simek
2008-01-27 10:41 ` [PATCH 01/52] [microblaze] Kconfig patches v2 Michal Simek
2008-01-27 17:15 ` Randy Dunlap
2008-01-27 11:59 ` Microblaze init port Geert Uytterhoeven
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e83ac9f205e3ef0524ded397faf91a7a0750100c.1201107832.git.monstr@monstr.eu \
--to=monstr@monstr.eu \
--cc=john.williams@petalogix.com \
--cc=linux-kernel@vger.kernel.org \
--cc=microblaze-uclinux@itee.uq.edu.au \
--cc=stephen.neuendorffer@xilinx.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).