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,
switch (call) {
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:
return sys_semget (first, second, third);
case SEMCTL: {
......
......@@ -2124,6 +2124,7 @@ struct ipc_kludge {
#define SEMOP 1
#define SEMGET 2
#define SEMCTL 3
#define SEMTIMEDOP 4
#define MSGSND 11
#define MSGRCV 12
#define MSGGET 13
......
......@@ -1254,7 +1254,7 @@ sys_call_table:
data8 sys_epoll_create
data8 sys_epoll_ctl
data8 sys_epoll_wait // 1245
data8 ia64_ni_syscall
data8 sys_semtimedop
data8 ia64_ni_syscall
data8 ia64_ni_syscall
data8 ia64_ni_syscall
......
......@@ -14,6 +14,7 @@ struct ipc_kludge {
#define SEMOP 1
#define SEMGET 2
#define SEMCTL 3
#define SEMTIMEDOP 4
#define MSGSND 11
#define MSGRCV 12
#define MSGGET 13
......
......@@ -235,6 +235,7 @@
#define __NR_epoll_create 1243
#define __NR_epoll_ctl 1244
#define __NR_epoll_wait 1245
#define __NR_semtimedop 1246
#if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
......
......@@ -140,6 +140,8 @@ struct sysv_sem {
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_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__ */
......
......@@ -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>
......@@ -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)
{
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;
......@@ -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 */
......
......@@ -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;
......
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