On Fri, Jun 19, 2026 at 8:30 PM Warner Losh <[email protected]> wrote:

>
>
> On Fri, May 22, 2026 at 7:49 PM Pierrick Bouvier <
> [email protected]> wrote:
>
>> 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.
>>
>
> It's close, but the structures have slightly different layouts, so it's
> hard
> to refactor. I know there's an XXX comment suggesting that we should
> combine these, but I'd kinda like to postpone that. It may be that we'll
> just delete the kevent11 which may happen soon (we kept it long past
> the end of FreeBSD 11 support because it was one of the system calls
> that rust used, and that may finally be deployed widely enough to retire
> it).
>

I'm going to defer this.
https://github.com/qemu-bsd-user/qemu-bsd-user/issues/67
captures the suggestion, which I'll return to once I have the bulk of
the fork upstreamed and can focus on the (many many) code improvement
issues that are there.

Warner

Reply via email to