Commit f99a1a55 authored by Andrew Morton's avatar Andrew Morton Committed by Jaroslav Kysela

[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.
parent c7d7f43a
...@@ -140,7 +140,11 @@ asmlinkage int sys_ipc (uint call, int first, int second, ...@@ -140,7 +140,11 @@ asmlinkage int sys_ipc (uint call, int first, int second,
switch (call) { switch (call) {
case SEMOP: case SEMOP:
return sys_semop (first, (struct sembuf *)ptr, second); return sys_semtimedop (first, (struct sembuf *)ptr, second, NULL);
case SEMTIMEDOP:
return sys_semtimedop(first, (struct sembuf *)ptr, second,
(const struct timespec *)fifth);
case SEMGET: case SEMGET:
return sys_semget (first, second, third); return sys_semget (first, second, third);
case SEMCTL: { case SEMCTL: {
......
...@@ -2124,6 +2124,7 @@ struct ipc_kludge { ...@@ -2124,6 +2124,7 @@ struct ipc_kludge {
#define SEMOP 1 #define SEMOP 1
#define SEMGET 2 #define SEMGET 2
#define SEMCTL 3 #define SEMCTL 3
#define SEMTIMEDOP 4
#define MSGSND 11 #define MSGSND 11
#define MSGRCV 12 #define MSGRCV 12
#define MSGGET 13 #define MSGGET 13
......
...@@ -1254,7 +1254,7 @@ sys_call_table: ...@@ -1254,7 +1254,7 @@ sys_call_table:
data8 sys_epoll_create data8 sys_epoll_create
data8 sys_epoll_ctl data8 sys_epoll_ctl
data8 sys_epoll_wait // 1245 data8 sys_epoll_wait // 1245
data8 ia64_ni_syscall data8 sys_semtimedop
data8 ia64_ni_syscall data8 ia64_ni_syscall
data8 ia64_ni_syscall data8 ia64_ni_syscall
data8 ia64_ni_syscall data8 ia64_ni_syscall
......
...@@ -14,6 +14,7 @@ struct ipc_kludge { ...@@ -14,6 +14,7 @@ struct ipc_kludge {
#define SEMOP 1 #define SEMOP 1
#define SEMGET 2 #define SEMGET 2
#define SEMCTL 3 #define SEMCTL 3
#define SEMTIMEDOP 4
#define MSGSND 11 #define MSGSND 11
#define MSGRCV 12 #define MSGRCV 12
#define MSGGET 13 #define MSGGET 13
......
...@@ -235,6 +235,7 @@ ...@@ -235,6 +235,7 @@
#define __NR_epoll_create 1243 #define __NR_epoll_create 1243
#define __NR_epoll_ctl 1244 #define __NR_epoll_ctl 1244
#define __NR_epoll_wait 1245 #define __NR_epoll_wait 1245
#define __NR_semtimedop 1246
#if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
......
...@@ -140,6 +140,8 @@ struct sysv_sem { ...@@ -140,6 +140,8 @@ struct sysv_sem {
asmlinkage long sys_semget (key_t key, int nsems, int semflg); asmlinkage long sys_semget (key_t key, int nsems, int semflg);
asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops); asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops);
asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg); asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg);
asmlinkage long sys_semtimedop(int semid, struct sembuf *sops,
unsigned nsops, const struct timespec *timeout);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/time.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/security.h> #include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -968,6 +969,12 @@ static int alloc_undo(struct sem_array *sma, struct sem_undo** unp, int semid, i ...@@ -968,6 +969,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) 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; int error = -EINVAL;
struct sem_array *sma; struct sem_array *sma;
...@@ -976,7 +983,7 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -976,7 +983,7 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
struct sem_undo *un; struct sem_undo *un;
int undos = 0, decrease = 0, alter = 0; int undos = 0, decrease = 0, alter = 0;
struct sem_queue queue; struct sem_queue queue;
unsigned long jiffies_left = 0;
if (nsops < 1 || semid < 0) if (nsops < 1 || semid < 0)
return -EINVAL; return -EINVAL;
...@@ -991,6 +998,19 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -991,6 +998,19 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
error=-EFAULT; error=-EFAULT;
goto out_free; 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(); lock_semundo();
sma = sem_lock(semid); sma = sem_lock(semid);
error=-EINVAL; error=-EINVAL;
...@@ -1058,6 +1078,9 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -1058,6 +1078,9 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
sem_unlock(sma); sem_unlock(sma);
unlock_semundo(); unlock_semundo();
if (timeout)
jiffies_left = schedule_timeout(jiffies_left);
else
schedule(); schedule();
lock_semundo(); lock_semundo();
...@@ -1084,6 +1107,8 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -1084,6 +1107,8 @@ asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
break; break;
} else { } else {
error = queue.status; error = queue.status;
if (error == -EINTR && timeout && jiffies_left == 0)
error = -EAGAIN;
if (queue.prev) /* got Interrupt */ if (queue.prev) /* got Interrupt */
break; break;
/* Everything done by update_queue */ /* Everything done by update_queue */
......
...@@ -562,6 +562,13 @@ asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops) ...@@ -562,6 +562,13 @@ asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops)
return -ENOSYS; 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) asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
{ {
return -ENOSYS; return -ENOSYS;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment