On 5/18/2026 2:27 PM, Warner Losh wrote:
> Add event notification system call shims: kqueue, freebsd11_kevent
> (legacy 32-bit data field), and kevent (with 64-bit ext fields).
> 
> Signed-off-by: Stacey Son <[email protected]>
> Signed-off-by: MikaĆ«l Urankar <[email protected]>
> Signed-off-by: Sean Bruno <[email protected]>
> Signed-off-by: Kyle Evans <[email protected]>
> Signed-off-by: Warner Losh <[email protected]>
> Assisted-by: Claude Opus 4.6 (1M context)
> ---
>  bsd-user/freebsd/os-time.h | 173 
> +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 173 insertions(+)
> 
> diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
> index 12c5ba02e8..078355392d 100644
> --- a/bsd-user/freebsd/os-time.h
> +++ b/bsd-user/freebsd/os-time.h
> @@ -629,5 +629,178 @@ static inline abi_long do_freebsd_ppoll(CPUArchState 
> *env, abi_long arg1,
>  }
>  
>  /* kqueue(2) */
> +static inline abi_long do_freebsd_kqueue(void)
> +{
> +
> +    return get_errno(kqueue());
> +}
> +
> +/* kevent(2) */
> +/* XXX Maybe some day, consolidate these two... */
> +static inline abi_long do_freebsd_freebsd11_kevent(abi_long arg1,
> +    abi_ulong arg2, abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long 
> arg6)
> +{
> +    abi_long ret;
> +    struct kevent *changelist = NULL, *eventlist = NULL;
> +    struct target_freebsd11_kevent *target_changelist, *target_eventlist;
> +    struct timespec ts;
> +    int i;
> +
> +    if (arg3 != 0) {
> +        target_changelist = lock_user(VERIFY_READ, arg2,
> +                                      sizeof(*target_changelist) * arg3, 1);
> +        if (target_changelist == NULL) {
> +            return -TARGET_EFAULT;
> +        }
> +
> +        changelist = alloca(sizeof(struct kevent) * arg3);
> +        memset(changelist, '\0', sizeof(struct kevent) * arg3);
> +        for (i = 0; i < arg3; i++) {
> +            __get_user(changelist[i].ident, &target_changelist[i].ident);
> +            __get_user(changelist[i].filter, &target_changelist[i].filter);
> +            __get_user(changelist[i].flags, &target_changelist[i].flags);
> +            __get_user(changelist[i].fflags, &target_changelist[i].fflags);
> +            __get_user(changelist[i].data, &target_changelist[i].data);
> +            /* __get_user(changelist[i].udata, &target_changelist[i].udata); 
> */
> +#if TARGET_ABI_BITS == 32
> +            changelist[i].udata = (void 
> *)(uintptr_t)target_changelist[i].udata;
> +            tswap32s((uint32_t *)&changelist[i].udata);
> +#else
> +            changelist[i].udata = (void 
> *)(uintptr_t)target_changelist[i].udata;
> +            tswap64s((uint64_t *)&changelist[i].udata);
> +#endif
> +        }
> +        unlock_user(target_changelist, arg2, sizeof(*target_changelist) * 
> arg3);
> +    }
> +
> +    if (arg5 != 0) {
> +        eventlist = alloca(sizeof(struct kevent) * arg5);
> +    }
> +    if (arg6 != 0) {
> +        if (t2h_freebsd_timespec(&ts, arg6)) {
> +            return -TARGET_EFAULT;
> +        }
> +    }
> +    ret = get_errno(safe_kevent(arg1, changelist, arg3, eventlist, arg5,
> +                                arg6 != 0 ? &ts : NULL));
> +
> +    if (arg5 == 0) {
> +        return ret;
> +    }
> +
> +    if (!is_error(ret)) {
> +        target_eventlist = lock_user(VERIFY_WRITE, arg4,
> +                                     sizeof(*target_eventlist) * arg5, 0);
> +        if (target_eventlist == NULL) {
> +            return -TARGET_EFAULT;
> +        }
> +        for (i = 0; i < ret; i++) {
> +            __put_user(eventlist[i].ident, &target_eventlist[i].ident);
> +            __put_user(eventlist[i].filter, &target_eventlist[i].filter);
> +            __put_user(eventlist[i].flags, &target_eventlist[i].flags);
> +            __put_user(eventlist[i].fflags, &target_eventlist[i].fflags);
> +            __put_user(eventlist[i].data, &target_eventlist[i].data);
> +            /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/
> +#if TARGET_ABI_BITS == 32
> +            tswap32s((uint32_t *)&eventlist[i].udata);
> +            target_eventlist[i].udata = (uintptr_t)eventlist[i].udata;
> +#else
> +            tswap64s((uint64_t *)&eventlist[i].udata);
> +            target_eventlist[i].udata = (uintptr_t)eventlist[i].udata;
> +#endif
> +        }
> +        unlock_user(target_eventlist, arg4,
> +                    sizeof(*target_eventlist) * ret);
> +    }
> +    return ret;
> +}
> +
> +/* kevent(2) */
> +static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
> +        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
> +{
> +    abi_long ret;
> +    struct kevent *changelist = NULL, *eventlist = NULL;
> +    struct target_freebsd_kevent *target_changelist, *target_eventlist;
> +    struct timespec ts;
> +    int i;
> +
> +    if (arg3 != 0) {
> +        target_changelist = lock_user(VERIFY_READ, arg2,
> +                sizeof(struct target_freebsd_kevent) * arg3, 1);
> +        if (target_changelist == NULL) {
> +            return -TARGET_EFAULT;
> +        }
> +
> +        changelist = alloca(sizeof(struct kevent) * arg3);
> +        for (i = 0; i < arg3; i++) {
> +            __get_user(changelist[i].ident, &target_changelist[i].ident);
> +            __get_user(changelist[i].filter, &target_changelist[i].filter);
> +            __get_user(changelist[i].flags, &target_changelist[i].flags);
> +            __get_user(changelist[i].fflags, &target_changelist[i].fflags);
> +            __get_user(changelist[i].data, &target_changelist[i].data);
> +            /* __get_user(changelist[i].udata, &target_changelist[i].udata); 
> */
> +#if TARGET_ABI_BITS == 32
> +            changelist[i].udata = (void 
> *)(uintptr_t)target_changelist[i].udata;
> +            tswap32s((uint32_t *)&changelist[i].udata);
> +#else
> +            changelist[i].udata = (void 
> *)(uintptr_t)target_changelist[i].udata;
> +            tswap64s((uint64_t *)&changelist[i].udata);
> +#endif
> +            __get_user(changelist[i].ext[0], &target_changelist[i].ext[0]);
> +            __get_user(changelist[i].ext[1], &target_changelist[i].ext[1]);
> +            __get_user(changelist[i].ext[2], &target_changelist[i].ext[2]);
> +            __get_user(changelist[i].ext[3], &target_changelist[i].ext[3]);
> +        }
> +        unlock_user(target_changelist, arg2, 0);
> +    }
> +
> +    if (arg5 != 0) {
> +        eventlist = alloca(sizeof(struct kevent) * arg5);
> +    }
> +    if (arg6 != 0) {
> +        if (t2h_freebsd_timespec(&ts, arg6)) {
> +            return -TARGET_EFAULT;
> +        }
> +    }
> +    ret = get_errno(safe_kevent(arg1, changelist, arg3, eventlist, arg5,
> +                                arg6 != 0 ? &ts : NULL));
> +
> +    if (arg5 == 0) {
> +        return ret;
> +    }
> +
> +    if (!is_error(ret)) {
> +        target_eventlist = lock_user(VERIFY_WRITE, arg4,
> +            sizeof(struct target_freebsd_kevent) * arg5, 0);
> +        if (target_eventlist == NULL) {
> +            return -TARGET_EFAULT;
> +        }
> +        for (i = 0; i < ret; i++) {
> +            __put_user(eventlist[i].ident, &target_eventlist[i].ident);
> +            __put_user(eventlist[i].filter, &target_eventlist[i].filter);
> +            __put_user(eventlist[i].flags, &target_eventlist[i].flags);
> +            __put_user(eventlist[i].fflags, &target_eventlist[i].fflags);
> +            __put_user(eventlist[i].data, &target_eventlist[i].data);
> +            /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/
> +#if TARGET_ABI_BITS == 32
> +            tswap32s((uint32_t *)&eventlist[i].udata);
> +            target_eventlist[i].udata = (uintptr_t)eventlist[i].udata;
> +#else
> +            tswap64s((uint64_t *)&eventlist[i].udata);
> +            target_eventlist[i].udata = (uintptr_t)eventlist[i].udata;
> +#endif
> +            __put_user(eventlist[i].ext[0], &target_eventlist[i].ext[0]);
> +            __put_user(eventlist[i].ext[1], &target_eventlist[i].ext[1]);
> +            __put_user(eventlist[i].ext[2], &target_eventlist[i].ext[2]);
> +            __put_user(eventlist[i].ext[3], &target_eventlist[i].ext[3]);
> +        }
> +        unlock_user(target_eventlist, arg4,
> +                sizeof(struct target_freebsd_kevent) * ret);
> +    }
> +    return ret;
> +}
> +
> +/* sigtimedwait(2) */
>  
>  #endif /* FREEBSD_OS_TIME_H */
> 

If I understand correctly, the difference between the two is only in
get/put user for eventlist[i].ext[*].
It seems worth to factorize the two and add a parameter to switch
between the two.

Reply via email to