Review of System V Semaphore details

A review of system V semaphore details:
- implementation details on the semop() system call.
- the exact update rules for sem_otime and sem_ctime.

Opengroup man pages:

semget()
sem_otime is set to 0 and sem_ctime is set to current time.

sys_sem.h
sem_otime: Last semop
sem_ctime: Last time changed by semctl
It is undefined which changes are relevant:
- semaphore value changed with semctl(SETALL/SETVAL) [Linux]
- permissions changed with semctl(IPC_SET)? [Linux, all other]

Group 1a:

sem_otime is semop_time, sem_ctime is sem_createtime, IPC_SET considered as "change".
semop() without FIFO guarantee. per-semaphore event for waking up tasks.

Ultrics-3.1: sys/sys/sem.c
set to time:
sem_ctime: semget, semctl(IPC_SET)
sem_otime: semop() [all successful]
semop: no FIFO guarantee.
per-semaphore events, tasks wait on the first operation that blocks, with retry on wakeup.
Broadcast to all tasks waiting on a semaphore [in semop]
Notes:
per-semaphore event, broadcast to all tasks waiting on a semaphore [in usemop]
Notes:
- sem_otime is not updated by undos during exit() [see semexit()]
- The code appears to be copied from System V:
There is commented out code with a remark that a feature from System V is missing in Ultrics.

PDP11v: usr/src/uts/pdp11/os/sem.c
set to gethrestime_sec():
sem_ctime: semctl(IPC_SET), semget()
sem_otime: semop() [all successful]
semop: no FIFO guarantee.
per-semaphore events, tasks wait on the first operation that blocks, with retry on wakeup.
Broadcast to all tasks waiting on a semaphore [in semop]
Notes:
- No update to sem_otime in semexit().
- Source matches to Ultrics to a large extend

Opensolaris: uts/common/syscall/sem.c
set to gethrestime_sec():
sem_ctime: semctl(IPC_SET), semget()
sem_otime: semop() [all successful]
semop: no FIFO guarantee.
per-semaphore events, tasks wait on the first operation that blocks, with retry on wakeup.
Broadcast to all tasks waiting on a semaphore, with optimization for binary semaphores [in semop]
Notes:
- No update to sem_otime in semexit().

Group 1b:

sem_otime is semop_time, sem_ctime is sem_createtime, IPC_SET considered as "change".
semop() without FIFO guarantee. per-semaphore array event for waking up tasks.

freebsd 8.0: sys/kern/sysv_sem.c
set to time_seconds:
sem_ctime: semget, semctl(IPC_SET)
sem_otime: semop() [all successful]
semop: no FIFO guarantee.
single per-array event, tasks wait on the event.
semop calls that modify the array do a broadcast.
Note:
- sem_otime is not updated by undos during exit() [see semexit_myhook()]

FreeBSD 5.3: sys/kern/sysv_sem.c
set to time_seconds:
sem_ctime: semget, semctl(IPC_SET)
sem_otime: semop() [all successful]
semop: no FIFO guarantee.
single per-array event, tasks wait on the event.
semop calls that modify the array do a broadcast.
Note:
- sem_otime is not updated by undos during exit() [see semexit_myhook()]

XNU (Apple Darwin)
set to sysv_semtime:
sem_ctime: semget, semctl(IPC_SET)
sem_otime: semop() [all successful]
semop: no FIFO guarantee.
single per-array event, tasks wait on the event.
semop calls that modify the array do a broadcast.
Note:
- sem_otime is not updated by undos during exit() [see semexit()]

Code 2: Linux

sem_otime is semop_time, sem_ctime is sem_createtime, IPC_SET, SETALL and SETVAL considered as "change".

linux-0.99.10: ipc/sem.c
set to CURRENT_TIME:
sem_ctime: newary, semctl(SETVAL), semctl(IPC_SET), semctl(SETALL)
sem_otime: semop [all successful], sem_exit (UNDO)
Note:
- Initial Linux version with SysV sem.
- sem_ctime is copied with memcpy_tofs(), thus no read accesses to sem_ctime.

linux-1.0.9: ipc/sem.c
set to CURRENT_TIME:
sem_ctime: newary, semctl(SETVAL), semctl(IPC_SET), semctl(SETALL)
sem_otime: semop [all successful], sem_exit (UNDO)

linux-1.2.13: ipc/sem.c
set to CURRENT_TIME:
sem_ctime: semget() [in newary()], semctl(SETVAL), semctl(IPC_SET), semctl(SETALL)
sem_otime: sys_semop() [all successful, in do_semop(), update_queue()], sem_exit (UNDO)

linux-2.0.40: ipc/sem.c
set to CURRENT_TIME:
sem_ctime: semget() [in newary()], semctl(SETVAL), semctl(IPC_SET), semctl(SETALL)
sem_otime: sys_semop() [all successful, in do_semop(), update_queue()], sem_exit (UNDO)

linux-2.2.26: ipc/sem.c
set to CURRENT_TIME:
sem_ctime: semget() [in newary()], semctl(SETVAL), semctl(IPC_SET), semctl(SETALL)
sem_otime: sys_semop() [all successful, in do_semop(), update_queue()], sem_exit (UNDO)

linux-2.4.22: ipc/sem.c
set to CURRENT_TIME:
sem_ctime: semget() [in newary()], semctl(SETVAL), semctl(IPC_SET), semctl(SETALL)
sem_otime: sys_semop() [all, in do_semop(), update_queue()], sem_exit (UNDO)

linux-2.6.33.2: ipc/sem.c
set to get_seconds():
sem_ctime: semget() [in newary()], semctl(SETVAL), semctl(IPC_SET), semctl(SETALL)
sem_otime: sys_semop() [all successful, in do_semop(), update_queue()], sem_exit (UNDO)
semop: FIFO guaranteed.
dual per-array and per-semaphore list [in update_queue: semqueue->list]

Code 3: Coherent

Coherent 4.2: /conf/sem/src/sem386.c
set to posix_current_time():
sem_ctime: semget [in usemget()], semctl(IPC_SET), semctl(SETVAL), semctl(IPC_SET), semctl(SETALL), exit() [in semAllAdjust()], semop() [write]
sem_otime: semop() [all successful]
semop: no FIFO guarantee.
per-semaphore event, broadcast to all tasks waiting on a semaphore [in usemop]
Notes:
- "sem_ctime" is interpreted as sem_changetime. sem_otime as semop_time.

Summary: - BSD, Ultrics, OpenSolaris identical:
sem_ctime is semaphore create time [IPC_SET is considered as create]
sem_otime is semop() time
- Linux differs a bit
- My patch is wrong: sem_otime must be updated even if a wait-for-zero task was woken up.
- Coherent differs completely.