[PATCH v4 3/3] sysv: linux: Pass 64-bit version of semctl syscall
Alistair Francis
alistair.francis@wdc.com
Thu Mar 26 16:37:24 GMT 2020
The semctl_syscall() function passes a union semun to the kernel. The
union includes struct semid_ds as a member. On 32-bit architectures the
Linux kernel provides a *_high version of the 32-bit sem_otime and
sem_ctime values. These can be combined to get a 64-bit version of the
time.
This patch adjusts the struct semid_ds to support the *_high versions
of sem_otime and sem_ctime. For 32-bit systems with a 64-bit time_t
this can be used to get a 64-bit time from the two 32-bit values.
Due to allignment differences between 64-bit and 32-bit variables we
also need to set nsems to ensure it's correct.
---
sysdeps/unix/sysv/linux/bits/semid_ds_t.h | 15 ++++++++++++
.../unix/sysv/linux/hppa/bits/semid_ds_t.h | 15 ++++++++++++
.../unix/sysv/linux/mips/bits/semid_ds_t.h | 13 ++++++++++
.../unix/sysv/linux/powerpc/bits/semid_ds_t.h | 15 ++++++++++++
sysdeps/unix/sysv/linux/semctl.c | 24 +++++++++++++++----
.../unix/sysv/linux/sparc/bits/semid_ds_t.h | 15 ++++++++++++
sysdeps/unix/sysv/linux/x86/bits/semid_ds_t.h | 15 ++++++++++++
7 files changed, 108 insertions(+), 4 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/bits/semid_ds_t.h b/sysdeps/unix/sysv/linux/bits/semid_ds_t.h
index d9d902ed0d..b135301356 100644
--- a/sysdeps/unix/sysv/linux/bits/semid_ds_t.h
+++ b/sysdeps/unix/sysv/linux/bits/semid_ds_t.h
@@ -20,6 +20,21 @@
# error "Never include <bits/semid_ds_t.h> directly; use <sys/sem.h> instead."
#endif
+#if __WORDSIZE == 32
+/* This is the "new" y2038 types defined after the 5.1 kernel. It allows
+ * the kernel to use {o,c}time{_high} values to support a 64-bit time_t. */
+struct __semid_ds32 {
+ struct ipc_perm sem_perm; /* operation permission struct */
+ __syscall_ulong_t sem_otime; /* last semop() time */
+ __syscall_ulong_t sem_otime_high; /* last semop() time high */
+ __syscall_ulong_t sem_ctime; /* last time changed by semctl() */
+ __syscall_ulong_t sem_ctime_high; /* last time changed by semctl() high */
+ __syscall_ulong_t sem_nsems; /* number of semaphores in set */
+ __syscall_ulong_t __glibc_reserved3;
+ __syscall_ulong_t __glibc_reserved4;
+};
+#endif
+
/* Data structure describing a set of semaphores. */
#if __TIMESIZE == 32
struct semid_ds
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/semid_ds_t.h b/sysdeps/unix/sysv/linux/hppa/bits/semid_ds_t.h
index 39c0e53f38..3613c5ec94 100644
--- a/sysdeps/unix/sysv/linux/hppa/bits/semid_ds_t.h
+++ b/sysdeps/unix/sysv/linux/hppa/bits/semid_ds_t.h
@@ -20,6 +20,21 @@
# error "Never include <bits/semid_ds_t.h> directly; use <sys/sem.h> instead."
#endif
+#if __WORDSIZE == 32
+/* This is the "new" y2038 types defined after the 5.1 kernel. It allows
+ * the kernel to use {o,c}time{_high} values to support a 64-bit time_t. */
+struct __semid_ds32 {
+ struct ipc_perm sem_perm; /* operation permission struct */
+ __syscall_ulong_t sem_otime_high; /* last semop() time high */
+ __syscall_ulong_t sem_otime; /* last semop() time */
+ __syscall_ulong_t sem_ctime_high; /* last time changed by semctl() high */
+ __syscall_ulong_t sem_ctime; /* last time changed by semctl() */
+ __syscall_ulong_t sem_nsems; /* number of semaphores in set */
+ __syscall_ulong_t __glibc_reserved3;
+ __syscall_ulong_t __glibc_reserved4;
+};
+#endif
+
/* Data structure describing a set of semaphores. */
#if __TIMESIZE == 32
struct semid_ds
diff --git a/sysdeps/unix/sysv/linux/mips/bits/semid_ds_t.h b/sysdeps/unix/sysv/linux/mips/bits/semid_ds_t.h
index 1ab16492dd..e26906a67f 100644
--- a/sysdeps/unix/sysv/linux/mips/bits/semid_ds_t.h
+++ b/sysdeps/unix/sysv/linux/mips/bits/semid_ds_t.h
@@ -20,6 +20,19 @@
# error "Never include <bits/semid_ds_t.h> directly; use <sys/sem.h> instead."
#endif
+#if __WORDSIZE == 32
+/* This is the "new" y2038 types defined after the 5.1 kernel. It allows
+ * the kernel to use {o,c}time{_high} values to support a 64-bit time_t. */
+struct __semid_ds32 {
+ struct ipc_perm sem_perm; /* operation permission struct */
+ __syscall_ulong_t sem_otime; /* last semop time */
+ __syscall_ulong_t sem_ctime; /* last change time */
+ __syscall_ulong_t sem_nsems; /* number of semaphores in set */
+ __syscall_ulong_t sem_otime_high;
+ __syscall_ulong_t sem_ctime_high;
+};
+#endif
+
/* Data structure describing a set of semaphores. */
struct semid_ds
{
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/semid_ds_t.h b/sysdeps/unix/sysv/linux/powerpc/bits/semid_ds_t.h
index 79b4cba939..ec2ff552eb 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/semid_ds_t.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/semid_ds_t.h
@@ -20,6 +20,21 @@
# error "Never include <bits/semid_ds_t.h> directly; use <sys/sem.h> instead."
#endif
+#if __WORDSIZE == 32
+/* This is the "new" y2038 types defined after the 5.1 kernel. It allows
+ * the kernel to use {o,c}time{_high} values to support a 64-bit time_t. */
+struct __semid_ds32 {
+ struct ipc_perm sem_perm; /* operation permission struct */
+ __syscall_ulong_t sem_otime_high; /* last semop() time high */
+ __syscall_ulong_t sem_otime; /* last semop() time */
+ __syscall_ulong_t sem_ctime_high; /* last time changed by semctl() high */
+ __syscall_ulong_t sem_ctime; /* last time changed by semctl() */
+ __syscall_ulong_t sem_nsems; /* number of semaphores in set */
+ __syscall_ulong_t __glibc_reserved3;
+ __syscall_ulong_t __glibc_reserved4;
+};
+#endif
+
/* Data structure describing a set of semaphores. */
#if __TIMESIZE == 32
struct semid_ds
diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
index 30571af49f..38c2fc6545 100644
--- a/sysdeps/unix/sysv/linux/semctl.c
+++ b/sysdeps/unix/sysv/linux/semctl.c
@@ -29,6 +29,9 @@ union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
+#if __WORDSIZE == 32
+ struct __semid_ds32 *buf32; /* 32-bit buffer for IPC_STAT */
+#endif
unsigned short int *array; /* array for GETALL & SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
};
@@ -44,13 +47,26 @@ union semun
static int
semctl_syscall (int semid, int semnum, int cmd, union semun arg)
{
+ int ret;
#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
- return INLINE_SYSCALL_CALL (semctl, semid, semnum, cmd | __IPC_64,
- arg.array);
+ ret = INLINE_SYSCALL_CALL (semctl, semid, semnum, cmd | __IPC_64,
+ arg.array);
#else
- return INLINE_SYSCALL_CALL (ipc, IPCOP_semctl, semid, semnum, cmd | __IPC_64,
- SEMCTL_ARG_ADDRESS (arg));
+ ret = INLINE_SYSCALL_CALL (ipc, IPCOP_semctl, semid, semnum, cmd | __IPC_64,
+ SEMCTL_ARG_ADDRESS (arg));
#endif
+
+#if __WORDSIZE == 32 && __TIMESIZE == 64
+ if (ret == 0 && cmd == IPC_STAT)
+ {
+ arg.buf->sem_nsems = arg.buf32->sem_nsems;
+ arg.buf->sem_otime = arg.buf32->sem_otime |
+ ((time_t) arg.buf32->sem_otime_high << 32);
+ arg.buf->sem_ctime = arg.buf32->sem_ctime |
+ ((time_t) arg.buf32->sem_ctime_high << 32);
+ }
+#endif
+ return ret;
}
int
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/semid_ds_t.h b/sysdeps/unix/sysv/linux/sparc/bits/semid_ds_t.h
index f8de676e79..b08fb8a79e 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/semid_ds_t.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/semid_ds_t.h
@@ -20,6 +20,21 @@
# error "Never include <bits/semid_ds_t.h> directly; use <sys/sem.h> instead."
#endif
+#if __WORDSIZE == 32
+/* This is the "new" y2038 types defined after the 5.1 kernel. It allows
+ * the kernel to use {o,c}time{_high} values to support a 64-bit time_t. */
+struct __semid_ds32 {
+ struct ipc_perm sem_perm; /* operation permission struct */
+ __syscall_ulong_t sem_otime_high; /* last semop() time high */
+ __syscall_ulong_t sem_otime; /* last semop() time */
+ __syscall_ulong_t sem_ctime_high; /* last time changed by semctl() high */
+ __syscall_ulong_t sem_ctime; /* last time changed by semctl() */
+ __syscall_ulong_t sem_nsems; /* number of semaphores in set */
+ __syscall_ulong_t __glibc_reserved3;
+ __syscall_ulong_t __glibc_reserved4;
+};
+#endif
+
/* Data structure describing a set of semaphores. */
#if __TIMESIZE == 32
struct semid_ds
diff --git a/sysdeps/unix/sysv/linux/x86/bits/semid_ds_t.h b/sysdeps/unix/sysv/linux/x86/bits/semid_ds_t.h
index 42694069d5..c7b9adce88 100644
--- a/sysdeps/unix/sysv/linux/x86/bits/semid_ds_t.h
+++ b/sysdeps/unix/sysv/linux/x86/bits/semid_ds_t.h
@@ -20,6 +20,21 @@
# error "Never include <bits/semid_ds_t.h> directly; use <sys/sem.h> instead."
#endif
+#if __WORDSIZE == 32
+/* This is the "new" y2038 types defined after the 5.1 kernel. It allows
+ * the kernel to use {o,c}time{_high} values to support a 64-bit time_t. */
+struct __semid_ds32 {
+ struct ipc_perm sem_perm; /* operation permission struct */
+ __syscall_ulong_t sem_otime; /* last semop() time */
+ __syscall_ulong_t sem_otime_high; /* last semop() time high */
+ __syscall_ulong_t sem_ctime; /* last time changed by semctl() */
+ __syscall_ulong_t sem_ctime_high; /* last time changed by semctl() high */
+ __syscall_ulong_t sem_nsems; /* number of semaphores in set */
+ __syscall_ulong_t __glibc_reserved3;
+ __syscall_ulong_t __glibc_reserved4;
+};
+#endif
+
/* Data structure describing a set of semaphores. */
struct semid_ds
{
--
2.26.0
More information about the Libc-alpha
mailing list