[PATCH v7 2/2] sysv: linux: Pass 64-bit version of semctl syscall

Stepan Golosunov stepan@golosunov.pp.ru
Sun May 10 14:52:27 GMT 2020


On Sat, May 09, 2020 at 11:08:23AM -0700, Alistair Francis wrote:
> On Thu, May 7, 2020 at 12:44 PM Stepan Golosunov <stepan@golosunov.pp.ru> wrote:
> >
> > On Tue, May 05, 2020 at 08:47:36AM -0700, Alistair Francis wrote:
> > > 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.
> > >
> > > This change handles issues that would arrise with architectures that
> > > might select __TIMESIZE at build time (and result in different size
> > > semid_ds structs).
> > >
> > > As described by Adhemerval:
> > >   1. If an ABI issues 'semctl (semid, semnum, IPC_STAT, ...)' with
> > >      IPC_STAT without _IPC_CMD_TIME_64, the provided semid_ds buffer
> > >      will be used directly on the syscall.  This is the case for
> > >      64-bit architectures and 32-bit architecture without
> > >      __TIMESIZE==32 support (RV32 for instance).
> > >
> > >   2. If an ABI issues 'semctl (semid, semnum, IPC_STAT, ...)' with
> > >      IPC_STAT with _IPC_CMD_TIME_64 then __TIMESIZE==64 is implied.
> > >      A temporary __semid_ds32 will be used to issue the syscall and its
> > >      contents will be copied to users semid_ds buffer (which is also
> > >      implied to be the __TIMESIZE==64).
> >
> > As discussed elsewhere, __TIMESIZE description is incorrect here. It's
> > part of the abi and cannot be selected at build time.
> 
> Yep, but I'm a little confused what else to use.
> 
> We should only be using the *_high variables on 32-bit systems with a
> 64-bit time_t. So we need someway to check if that is the case.

Both programs with 64-bit time_t and 32-bit time_t will need to work
with the same glibc when __TIMESIZE==32.

> I could change the macros to only work for _WORDSIZE == 32 and then
> have a dynamic check on sizeof(time_t) == 8. Would that work?

sizeof(time_t) will probably work in user-included headers.  It won't
work inside glibc.

Either two different functions or presence of __IPC_CMD_TIME64 would
work inside glibc.  Neither of those is needed when __TIMESIZE==64.

> >
> > (And __IPC_CMD_TIME_64 is not actually required for __TIMESIZE==64
> > architectures like rv32.  If it is used on them it's just for
> > consistency.  Otherwise those architectures can be covered by
> > ((cmd & __IPC_CMD_TIME64) || (__TIMESIZE == 64))
> > conditions inside #if __IPC_TIME64 blocks.
> >
> > Or __IPC_CMD_TIME_64 could be not used at all. __TIMESIZE==32 support
> > can be implemented with the usual thin wrapper around __semctl64.
> > I suspect this would be preferable if not too costly.)
> 
> This isn't really the same as the usual wrappers though as there is no
> semctl64 syscall here.

It does not matter which syscalls are used to implement __semctl64
function.

I would suggest the following:

1. Forget about __IPC_CMD_TIME64.
2. Implement __TIMESIZE==64 on __WORDSIZE==32, making sure that on
__TIMESIZE==32 architectures nothing changes (previous versions of
the patch were approaching that goal).  Do not do any conversions in
semctl_syscall — it will be need in __semctl_mode16.

This would be good enough for rv32 and will not break anything.
After that y2038 support can be added to __TIMESIZE==32 architectures
with the following steps (there is a couple of alternative ways to do
it; this one is the usual one):

3. Make sure that struct __semid_ds64 exists on all architectures
(being the struct semid_ds on __TIMESIZE==64 architectures). It should
use __time64_t when __TIMESIZE==32.
4. Rename __new_semctl to __semctl (both in function definition and in
versioned_symbol).
5. Rename __semctl to __semctl64 (leaving versioned_symbol
untouched).  Make sure it accepts only __time64_t types (by changing
types and removing __TIMESIZE condition from __IPC_TIME64
definition).
6. When __TIMESIZE==64 #define __semctl64 __semctl before __semctl64
function definition.
7. When __TIMESIZE==32 implement __semctl function by copying
__semctl_mode16, changing semctl_syscall call to __semctl64 call and
adding conversions from __semid_ds64 to semid_ds when necessary.
Check whether libc_hidden_def (__semctl64) is needed for now.

This would get y2038 support for semctl to the same level as done in
other functions.  The next step will be done much later, as it depends
on all the y2038-affected functions:

8. Expose all y2038-changes (including __semctl64 function) to users
of the library when __TIMESIZE==32.


Additional note:
There will be 3 different types used for semid_ds:
Kernel (and semctl_syscall function) accepts struct semid64_ds (from
asm/sembuf.h).
__semctl64 will accept struct __semid_ds64.
__semctl will accept 32-bit struct semid_ds (which is different from
semid64_ds in sem_perm field).
__semctl_mode16 accepts semid64_ds (in cases where it's needed and
neither __semctl nor __semctl64 can deal with it).

(There is also 4th type, ancient struct semid_ds from linux/sem.h.
__old_semctl deals with it.)


More information about the Libc-alpha mailing list