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
