Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

futex: Add sys_futex_wait()

To complement sys_futex_waitv()/wake(), add sys_futex_wait(). This
syscall implements what was previously known as FUTEX_WAIT_BITSET
except it uses 'unsigned long' for the value and bitmask arguments,
takes timespec and clockid_t arguments for the absolute timeout and
uses FUTEX2 flags.

The 'unsigned long' allows FUTEX2_SIZE_U64 on 64bit platforms.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Link: https://lore.kernel.org/r/20230921105248.164324363@noisy.programming.kicks-ass.net

+156 -57
+1
arch/alpha/kernel/syscalls/syscall.tbl
··· 493 493 561 common cachestat sys_cachestat 494 494 562 common fchmodat2 sys_fchmodat2 495 495 563 common futex_wake sys_futex_wake 496 + 564 common futex_wait sys_futex_wait
+1
arch/arm/tools/syscall.tbl
··· 467 467 451 common cachestat sys_cachestat 468 468 452 common fchmodat2 sys_fchmodat2 469 469 454 common futex_wake sys_futex_wake 470 + 455 common futex_wait sys_futex_wait
+1 -1
arch/arm64/include/asm/unistd.h
··· 39 39 #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5) 40 40 #define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800) 41 41 42 - #define __NR_compat_syscalls 455 42 + #define __NR_compat_syscalls 456 43 43 #endif 44 44 45 45 #define __ARCH_WANT_SYS_CLONE
+2
arch/arm64/include/asm/unistd32.h
··· 913 913 __SYSCALL(__NR_fchmodat2, sys_fchmodat2) 914 914 #define __NR_futex_wake 454 915 915 __SYSCALL(__NR_futex_wake, sys_futex_wake) 916 + #define __NR_futex_wait 455 917 + __SYSCALL(__NR_futex_wait, sys_futex_wait) 916 918 917 919 /* 918 920 * Please add new compat syscalls above this comment and update
+1
arch/ia64/kernel/syscalls/syscall.tbl
··· 374 374 451 common cachestat sys_cachestat 375 375 452 common fchmodat2 sys_fchmodat2 376 376 454 common futex_wake sys_futex_wake 377 + 455 common futex_wait sys_futex_wait
+1
arch/m68k/kernel/syscalls/syscall.tbl
··· 453 453 451 common cachestat sys_cachestat 454 454 452 common fchmodat2 sys_fchmodat2 455 455 454 common futex_wake sys_futex_wake 456 + 455 common futex_wait sys_futex_wait
+1
arch/microblaze/kernel/syscalls/syscall.tbl
··· 459 459 451 common cachestat sys_cachestat 460 460 452 common fchmodat2 sys_fchmodat2 461 461 454 common futex_wake sys_futex_wake 462 + 455 common futex_wait sys_futex_wait
+1
arch/mips/kernel/syscalls/syscall_n32.tbl
··· 392 392 451 n32 cachestat sys_cachestat 393 393 452 n32 fchmodat2 sys_fchmodat2 394 394 454 n32 futex_wake sys_futex_wake 395 + 455 n32 futex_wait sys_futex_wait
+1
arch/mips/kernel/syscalls/syscall_n64.tbl
··· 368 368 451 n64 cachestat sys_cachestat 369 369 452 n64 fchmodat2 sys_fchmodat2 370 370 454 n64 futex_wake sys_futex_wake 371 + 455 n64 futex_wait sys_futex_wait
+1
arch/mips/kernel/syscalls/syscall_o32.tbl
··· 441 441 451 o32 cachestat sys_cachestat 442 442 452 o32 fchmodat2 sys_fchmodat2 443 443 454 o32 futex_wake sys_futex_wake 444 + 455 o32 futex_wait sys_futex_wait
+1
arch/parisc/kernel/syscalls/syscall.tbl
··· 452 452 451 common cachestat sys_cachestat 453 453 452 common fchmodat2 sys_fchmodat2 454 454 454 common futex_wake sys_futex_wake 455 + 455 common futex_wait sys_futex_wait
+1
arch/powerpc/kernel/syscalls/syscall.tbl
··· 540 540 451 common cachestat sys_cachestat 541 541 452 common fchmodat2 sys_fchmodat2 542 542 454 common futex_wake sys_futex_wake 543 + 455 common futex_wait sys_futex_wait
+1
arch/s390/kernel/syscalls/syscall.tbl
··· 456 456 451 common cachestat sys_cachestat sys_cachestat 457 457 452 common fchmodat2 sys_fchmodat2 sys_fchmodat2 458 458 454 common futex_wake sys_futex_wake sys_futex_wake 459 + 455 common futex_wait sys_futex_wait sys_futex_wait
+1
arch/sh/kernel/syscalls/syscall.tbl
··· 456 456 451 common cachestat sys_cachestat 457 457 452 common fchmodat2 sys_fchmodat2 458 458 454 common futex_wake sys_futex_wake 459 + 455 common futex_wait sys_futex_wait
+1
arch/sparc/kernel/syscalls/syscall.tbl
··· 499 499 451 common cachestat sys_cachestat 500 500 452 common fchmodat2 sys_fchmodat2 501 501 454 common futex_wake sys_futex_wake 502 + 455 common futex_wait sys_futex_wait
+1
arch/x86/entry/syscalls/syscall_32.tbl
··· 458 458 451 i386 cachestat sys_cachestat 459 459 452 i386 fchmodat2 sys_fchmodat2 460 460 454 i386 futex_wake sys_futex_wake 461 + 455 i386 futex_wait sys_futex_wait
+1
arch/x86/entry/syscalls/syscall_64.tbl
··· 376 376 452 common fchmodat2 sys_fchmodat2 377 377 453 64 map_shadow_stack sys_map_shadow_stack 378 378 454 common futex_wake sys_futex_wake 379 + 455 common futex_wait sys_futex_wait 379 380 380 381 # 381 382 # Due to a historical design error, certain syscalls are numbered differently
+1
arch/xtensa/kernel/syscalls/syscall.tbl
··· 424 424 451 common cachestat sys_cachestat 425 425 452 common fchmodat2 sys_fchmodat2 426 426 454 common futex_wake sys_futex_wake 427 + 455 common futex_wait sys_futex_wait
+4
include/linux/syscalls.h
··· 552 552 553 553 asmlinkage long sys_futex_wake(void __user *uaddr, unsigned long mask, int nr, unsigned int flags); 554 554 555 + asmlinkage long sys_futex_wait(void __user *uaddr, unsigned long val, unsigned long mask, 556 + unsigned int flags, struct __kernel_timespec __user *timespec, 557 + clockid_t clockid); 558 + 555 559 asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp, 556 560 struct __kernel_timespec __user *rmtp); 557 561 asmlinkage long sys_nanosleep_time32(struct old_timespec32 __user *rqtp,
+3 -1
include/uapi/asm-generic/unistd.h
··· 824 824 __SYSCALL(__NR_fchmodat2, sys_fchmodat2) 825 825 #define __NR_futex_wake 454 826 826 __SYSCALL(__NR_futex_wake, sys_futex_wake) 827 + #define __NR_futex_wait 455 828 + __SYSCALL(__NR_futex_wait, sys_futex_wait) 827 829 828 830 #undef __NR_syscalls 829 - #define __NR_syscalls 455 831 + #define __NR_syscalls 456 830 832 831 833 /* 832 834 * 32 bit systems traditionally used different
+3
kernel/futex/futex.h
··· 332 332 u32 __user *uaddr2, int nr_wake, int nr_requeue, 333 333 u32 *cmpval, int requeue_pi); 334 334 335 + extern int __futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, 336 + struct hrtimer_sleeper *to, u32 bitset); 337 + 335 338 extern int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, 336 339 ktime_t *abs_time, u32 bitset); 337 340
+90 -30
kernel/futex/syscalls.c
··· 221 221 return 0; 222 222 } 223 223 224 + static int futex2_setup_timeout(struct __kernel_timespec __user *timeout, 225 + clockid_t clockid, struct hrtimer_sleeper *to) 226 + { 227 + int flag_clkid = 0, flag_init = 0; 228 + struct timespec64 ts; 229 + ktime_t time; 230 + int ret; 231 + 232 + if (!timeout) 233 + return 0; 234 + 235 + if (clockid == CLOCK_REALTIME) { 236 + flag_clkid = FLAGS_CLOCKRT; 237 + flag_init = FUTEX_CLOCK_REALTIME; 238 + } 239 + 240 + if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC) 241 + return -EINVAL; 242 + 243 + if (get_timespec64(&ts, timeout)) 244 + return -EFAULT; 245 + 246 + /* 247 + * Since there's no opcode for futex_waitv, use 248 + * FUTEX_WAIT_BITSET that uses absolute timeout as well 249 + */ 250 + ret = futex_init_timeout(FUTEX_WAIT_BITSET, flag_init, &ts, &time); 251 + if (ret) 252 + return ret; 253 + 254 + futex_setup_timer(&time, to, flag_clkid, 0); 255 + return 0; 256 + } 257 + 258 + static inline void futex2_destroy_timeout(struct hrtimer_sleeper *to) 259 + { 260 + hrtimer_cancel(&to->timer); 261 + destroy_hrtimer_on_stack(&to->timer); 262 + } 263 + 224 264 /** 225 265 * sys_futex_waitv - Wait on a list of futexes 226 266 * @waiters: List of futexes to wait on ··· 290 250 { 291 251 struct hrtimer_sleeper to; 292 252 struct futex_vector *futexv; 293 - struct timespec64 ts; 294 - ktime_t time; 295 253 int ret; 296 254 297 255 /* This syscall supports no flags for now */ ··· 299 261 if (!nr_futexes || nr_futexes > FUTEX_WAITV_MAX || !waiters) 300 262 return -EINVAL; 301 263 302 - if (timeout) { 303 - int flag_clkid = 0, flag_init = 0; 304 - 305 - if (clockid == CLOCK_REALTIME) { 306 - flag_clkid = FLAGS_CLOCKRT; 307 - flag_init = FUTEX_CLOCK_REALTIME; 308 - } 309 - 310 - if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC) 311 - return -EINVAL; 312 - 313 - if (get_timespec64(&ts, timeout)) 314 - return -EFAULT; 315 - 316 - /* 317 - * Since there's no opcode for futex_waitv, use 318 - * FUTEX_WAIT_BITSET that uses absolute timeout as well 319 - */ 320 - ret = futex_init_timeout(FUTEX_WAIT_BITSET, flag_init, &ts, &time); 321 - if (ret) 322 - return ret; 323 - 324 - futex_setup_timer(&time, &to, flag_clkid, 0); 325 - } 264 + if (timeout && (ret = futex2_setup_timeout(timeout, clockid, &to))) 265 + return ret; 326 266 327 267 futexv = kcalloc(nr_futexes, sizeof(*futexv), GFP_KERNEL); 328 268 if (!futexv) { ··· 315 299 kfree(futexv); 316 300 317 301 destroy_timer: 318 - if (timeout) { 319 - hrtimer_cancel(&to.timer); 320 - destroy_hrtimer_on_stack(&to.timer); 321 - } 302 + if (timeout) 303 + futex2_destroy_timeout(&to); 322 304 return ret; 323 305 } 324 306 ··· 348 334 return -EINVAL; 349 335 350 336 return futex_wake(uaddr, FLAGS_STRICT | flags, nr, mask); 337 + } 338 + 339 + /* 340 + * sys_futex_wait - Wait on a futex 341 + * @uaddr: Address of the futex to wait on 342 + * @val: Value of @uaddr 343 + * @mask: bitmask 344 + * @flags: FUTEX2 flags 345 + * @timeout: Optional absolute timeout 346 + * @clockid: Clock to be used for the timeout, realtime or monotonic 347 + * 348 + * Identical to the traditional FUTEX_WAIT_BITSET op, except it is part of the 349 + * futex2 familiy of calls. 350 + */ 351 + 352 + SYSCALL_DEFINE6(futex_wait, 353 + void __user *, uaddr, 354 + unsigned long, val, 355 + unsigned long, mask, 356 + unsigned int, flags, 357 + struct __kernel_timespec __user *, timeout, 358 + clockid_t, clockid) 359 + { 360 + struct hrtimer_sleeper to; 361 + int ret; 362 + 363 + if (flags & ~FUTEX2_VALID_MASK) 364 + return -EINVAL; 365 + 366 + flags = futex2_to_flags(flags); 367 + if (!futex_flags_valid(flags)) 368 + return -EINVAL; 369 + 370 + if (!futex_validate_input(flags, val) || 371 + !futex_validate_input(flags, mask)) 372 + return -EINVAL; 373 + 374 + if (timeout && (ret = futex2_setup_timeout(timeout, clockid, &to))) 375 + return ret; 376 + 377 + ret = __futex_wait(uaddr, flags, val, timeout ? &to : NULL, mask); 378 + 379 + if (timeout) 380 + futex2_destroy_timeout(&to); 381 + 382 + return ret; 351 383 } 352 384 353 385 #ifdef CONFIG_COMPAT
+36 -25
kernel/futex/waitwake.c
··· 632 632 return ret; 633 633 } 634 634 635 - int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, ktime_t *abs_time, u32 bitset) 635 + int __futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, 636 + struct hrtimer_sleeper *to, u32 bitset) 636 637 { 637 - struct hrtimer_sleeper timeout, *to; 638 - struct restart_block *restart; 639 - struct futex_hash_bucket *hb; 640 638 struct futex_q q = futex_q_init; 639 + struct futex_hash_bucket *hb; 641 640 int ret; 642 641 643 642 if (!bitset) 644 643 return -EINVAL; 644 + 645 645 q.bitset = bitset; 646 646 647 - to = futex_setup_timer(abs_time, &timeout, flags, 648 - current->timer_slack_ns); 649 647 retry: 650 648 /* 651 649 * Prepare to wait on uaddr. On success, it holds hb->lock and q ··· 651 653 */ 652 654 ret = futex_wait_setup(uaddr, val, flags, &q, &hb); 653 655 if (ret) 654 - goto out; 656 + return ret; 655 657 656 658 /* futex_queue and wait for wakeup, timeout, or a signal. */ 657 659 futex_wait_queue(hb, &q, to); 658 660 659 661 /* If we were woken (and unqueued), we succeeded, whatever. */ 660 - ret = 0; 661 662 if (!futex_unqueue(&q)) 662 - goto out; 663 - ret = -ETIMEDOUT; 663 + return 0; 664 + 664 665 if (to && !to->task) 665 - goto out; 666 + return -ETIMEDOUT; 666 667 667 668 /* 668 669 * We expect signal_pending(current), but we might be the ··· 670 673 if (!signal_pending(current)) 671 674 goto retry; 672 675 673 - ret = -ERESTARTSYS; 674 - if (!abs_time) 675 - goto out; 676 + return -ERESTARTSYS; 677 + } 676 678 677 - restart = &current->restart_block; 678 - restart->futex.uaddr = uaddr; 679 - restart->futex.val = val; 680 - restart->futex.time = *abs_time; 681 - restart->futex.bitset = bitset; 682 - restart->futex.flags = flags | FLAGS_HAS_TIMEOUT; 679 + int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, ktime_t *abs_time, u32 bitset) 680 + { 681 + struct hrtimer_sleeper timeout, *to; 682 + struct restart_block *restart; 683 + int ret; 683 684 684 - ret = set_restart_fn(restart, futex_wait_restart); 685 + to = futex_setup_timer(abs_time, &timeout, flags, 686 + current->timer_slack_ns); 685 687 686 - out: 687 - if (to) { 688 - hrtimer_cancel(&to->timer); 689 - destroy_hrtimer_on_stack(&to->timer); 688 + ret = __futex_wait(uaddr, flags, val, to, bitset); 689 + 690 + /* No timeout, nothing to clean up. */ 691 + if (!to) 692 + return ret; 693 + 694 + hrtimer_cancel(&to->timer); 695 + destroy_hrtimer_on_stack(&to->timer); 696 + 697 + if (ret == -ERESTARTSYS) { 698 + restart = &current->restart_block; 699 + restart->futex.uaddr = uaddr; 700 + restart->futex.val = val; 701 + restart->futex.time = *abs_time; 702 + restart->futex.bitset = bitset; 703 + restart->futex.flags = flags | FLAGS_HAS_TIMEOUT; 704 + 705 + return set_restart_fn(restart, futex_wait_restart); 690 706 } 707 + 691 708 return ret; 692 709 } 693 710
+1
kernel/sys_ni.c
··· 88 88 COND_SYSCALL_COMPAT(get_robust_list); 89 89 COND_SYSCALL(futex_waitv); 90 90 COND_SYSCALL(futex_wake); 91 + COND_SYSCALL(futex_wait); 91 92 COND_SYSCALL(kexec_load); 92 93 COND_SYSCALL_COMPAT(kexec_load); 93 94 COND_SYSCALL(init_module);