aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2002-12-14 03:16:52 -0800
committerJaroslav Kysela <perex@suse.cz>2002-12-14 03:16:52 -0800
commitf99a1a552f067b2352e2525ac72ddb499dd53ec4 (patch)
tree9808a54039941030abfddbb43dd58b904f7f7e28 /ipc
parentc7d7f43ab105fd26d6b0dcaa70b2e9b5cfcaeb09 (diff)
downloadhistory-f99a1a552f067b2352e2525ac72ddb499dd53ec4.tar.gz
[PATCH] semtimedop - semop() with a timeout
Patch from Mark Fasheh <mark.fasheh@oracle.com> (plus a few cleanups and a speedup from yours truly) Adds the semtimedop() function - semop with a timeout. Solaris has this. It's apparently worth a couple of percent to Oracle throughput and given the simplicity, that is sufficient benefit for inclusion IMO. This patch hooks up semtimedop() only for ia64 and ia32.
Diffstat (limited to 'ipc')
-rw-r--r--ipc/sem.c29
-rw-r--r--ipc/util.c7
2 files changed, 34 insertions, 2 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index 166f839d0995c4..c849b9375eebef 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -62,6 +62,7 @@
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/time.h>
#include <linux/smp_lock.h>
#include <linux/security.h>
#include <asm/uaccess.h>
@@ -969,6 +970,12 @@ static int alloc_undo(struct sem_array *sma, struct sem_undo** unp, int semid, i
asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
{
+ return sys_semtimedop(semid, tsops, nsops, NULL);
+}
+
+asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops,
+ unsigned nsops, const struct timespec *timeout)
+{
int error = -EINVAL;
struct sem_array *sma;
struct sembuf fast_sops[SEMOPM_FAST];
@@ -976,7 +983,7 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
struct sem_undo *un;
int undos = 0, decrease = 0, alter = 0;
struct sem_queue queue;
-
+ unsigned long jiffies_left = 0;
if (nsops < 1 || semid < 0)
return -EINVAL;
@@ -991,6 +998,19 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
error=-EFAULT;
goto out_free;
}
+ if (timeout) {
+ struct timespec _timeout;
+ if (copy_from_user(&_timeout, timeout, sizeof(*timeout))) {
+ error = -EFAULT;
+ goto out_free;
+ }
+ if (_timeout.tv_sec < 0 || _timeout.tv_nsec < 0 ||
+ _timeout.tv_nsec >= 1000000000L) {
+ error = -EINVAL;
+ goto out_free;
+ }
+ jiffies_left = timespec_to_jiffies(&_timeout);
+ }
lock_semundo();
sma = sem_lock(semid);
error=-EINVAL;
@@ -1058,7 +1078,10 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
sem_unlock(sma);
unlock_semundo();
- schedule();
+ if (timeout)
+ jiffies_left = schedule_timeout(jiffies_left);
+ else
+ schedule();
lock_semundo();
sma = sem_lock(semid);
@@ -1084,6 +1107,8 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
break;
} else {
error = queue.status;
+ if (error == -EINTR && timeout && jiffies_left == 0)
+ error = -EAGAIN;
if (queue.prev) /* got Interrupt */
break;
/* Everything done by update_queue */
diff --git a/ipc/util.c b/ipc/util.c
index 688bd2af4ef69e..a2f4c3b1c6805e 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -562,6 +562,13 @@ asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops)
return -ENOSYS;
}
+asmlinkage long sys_semtimedop(int semid, struct sembuf *sops, unsigned nsops,
+ const struct timespec *timeout)
+{
+ return -ENOSYS;
+}
+
+
asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
{
return -ENOSYS;