diff options
author | Andrew Morton <akpm@digeo.com> | 2002-12-14 03:16:52 -0800 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2002-12-14 03:16:52 -0800 |
commit | f99a1a552f067b2352e2525ac72ddb499dd53ec4 (patch) | |
tree | 9808a54039941030abfddbb43dd58b904f7f7e28 /ipc | |
parent | c7d7f43ab105fd26d6b0dcaa70b2e9b5cfcaeb09 (diff) | |
download | history-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.c | 29 | ||||
-rw-r--r-- | ipc/util.c | 7 |
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; |