diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 54143b288dc4..86b3d296f561 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -1,514 +1,514 @@ # @(#)Makefile.inc 8.3 (Berkeley) 10/24/94 # $FreeBSD$ # sys sources .PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/sys ${LIBC_SRCTOP}/sys # Include the generated makefile containing the *complete* list # of syscall names in MIASM. .include "${SRCTOP}/sys/sys/syscall.mk" # Include machine dependent definitions. # # MDASM names override the default syscall names in MIASM. # NOASM will prevent the default syscall code from being generated. # PSEUDO generates _() and __sys_() symbols, but not (). # # While historically machine dependent, all architectures have the following # declarations in common: # NOASM= exit.o \ getlogin.o \ sstk.o \ yield.o PSEUDO= _exit.o \ _getlogin.o .sinclude "${LIBC_SRCTOP}/${LIBC_ARCH}/sys/Makefile.inc" SRCS+= clock_gettime.c gettimeofday.c __vdso_gettimeofday.c NOASM+= clock_gettime.o gettimeofday.o PSEUDO+= _clock_gettime.o _gettimeofday.o # Sources common to both syscall interfaces: SRCS+= \ __error.c \ interposing_table.c SRCS+= getdents.c lstat.c mknod.c stat.c NOASM+= sched_getcpu.o PSEUDO+= _sched_getcpu.o SRCS+= fstat.c fstatat.c fstatfs.c getfsstat.c statfs.c NOASM+= fstat.o fstatat.o fstatfs.o getfsstat.o statfs.o PSEUDO+= _fstat.o _fstatat.o _fstatfs.o _getfsstat.o _statfs.o SRCS+= getdirentries.c NOASM+= getdirentries.o PSEUDO+= _getdirentries.o SRCS+= brk.c SRCS+= closefrom.c SRCS+= pipe.c SRCS+= shm_open.c SRCS+= vadvise.c SRCS+= POSIX2x_Fork.c SRCS+= compat-stub.c INTERPOSED = \ accept \ accept4 \ aio_suspend \ clock_nanosleep \ close \ connect \ fcntl \ fdatasync \ fsync \ fork \ kevent \ msync \ nanosleep \ open \ openat \ pdfork \ poll \ ppoll \ pselect \ ptrace \ read \ readv \ recvfrom \ recvmsg \ select \ sendmsg \ sendto \ setcontext \ sigaction \ sigprocmask \ sigsuspend \ sigtimedwait \ sigwait \ sigwaitinfo \ swapcontext \ wait4 \ wait6 \ write \ writev SRCS+= ${INTERPOSED:S/$/.c/} NOASM+= ${INTERPOSED:S/$/.o/} PSEUDO+= ${INTERPOSED:C/^.*$/_&.o/} # Add machine dependent asm sources: SRCS+=${MDASM} # Look though the complete list of syscalls (MIASM) for names that are # not defined with machine dependent implementations (MDASM) and are # not declared for no generation of default code (NOASM). Add each # syscall that satisfies these conditions to the ASM list. .for _asm in ${MIASM} .if (${MDASM:R:M${_asm:R}} == "") .if (${NOASM:R:M${_asm:R}} == "") ASM+=$(_asm) .endif .endif .endfor SASM= ${ASM:S/.o/.S/} SPSEUDO= ${PSEUDO:S/.o/.S/} SRCS+= ${SASM} ${SPSEUDO} SYM_MAPS+= ${LIBC_SRCTOP}/sys/Symbol.map # Generated files CLEANFILES+= ${SASM} ${SPSEUDO} .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" || \ ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "arm" NOTE_GNU_STACK='\t.section .note.GNU-stack,"",%%progbits\n' .else NOTE_GNU_STACK='' .endif ${SASM}: printf '/* %sgenerated by libc/sys/Makefile.inc */\n' @ > ${.TARGET} printf '#include "compat.h"\n' >> ${.TARGET} printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' >> ${.TARGET} printf ${NOTE_GNU_STACK} >>${.TARGET} ${SPSEUDO}: printf '/* %sgenerated by libc/sys/Makefile.inc */\n' @ > ${.TARGET} printf '#include "compat.h"\n' >> ${.TARGET} printf '#include "SYS.h"\nPSEUDO(${.PREFIX:S/_//})\n' \ >> ${.TARGET} printf ${NOTE_GNU_STACK} >>${.TARGET} MAN+= abort2.2 \ accept.2 \ access.2 \ acct.2 \ adjtime.2 \ aio_cancel.2 \ aio_error.2 \ aio_fsync.2 \ aio_mlock.2 \ aio_read.2 \ aio_return.2 \ aio_suspend.2 \ aio_waitcomplete.2 \ aio_write.2 \ bind.2 \ bindat.2 \ brk.2 \ cap_enter.2 \ cap_fcntls_limit.2 \ cap_ioctls_limit.2 \ cap_rights_limit.2 \ chdir.2 \ chflags.2 \ chmod.2 \ chown.2 \ chroot.2 \ clock_gettime.2 \ close.2 \ closefrom.2 \ connect.2 \ connectat.2 \ copy_file_range.2 \ cpuset.2 \ cpuset_getaffinity.2 \ cpuset_getdomain.2 \ dup.2 \ eventfd.2 \ execve.2 \ _exit.2 \ extattr_get_file.2 \ fcntl.2 \ ffclock.2 \ fhlink.2 \ fhopen.2 \ fhreadlink.2 \ flock.2 \ fork.2 \ fspacectl.2 \ fsync.2 \ getdirentries.2 \ getdtablesize.2 \ getfh.2 \ getfsstat.2 \ getgid.2 \ getgroups.2 \ getitimer.2 \ getlogin.2 \ getloginclass.2 \ getpeername.2 \ getpgrp.2 \ getpid.2 \ getpriority.2 \ getrandom.2 \ getrlimit.2 \ getrusage.2 \ getsid.2 \ getsockname.2 \ getsockopt.2 \ gettimeofday.2 \ getuid.2 \ intro.2 \ ioctl.2 \ issetugid.2 \ jail.2 \ kenv.2 \ kill.2 \ kldfind.2 \ kldfirstmod.2 \ kldload.2 \ kldnext.2 \ kldstat.2 \ kldsym.2 \ kldunload.2 \ kqueue.2 \ ktrace.2 \ link.2 \ lio_listio.2 \ listen.2 \ lseek.2 \ madvise.2 \ mincore.2 \ minherit.2 \ mkdir.2 \ mkfifo.2 \ mknod.2 \ mlock.2 \ mlockall.2 \ mmap.2 \ modfind.2 \ modnext.2 \ modstat.2 \ mount.2 \ mprotect.2 \ mq_close.2 \ mq_getattr.2 \ mq_notify.2 \ mq_open.2 \ mq_receive.2 \ mq_send.2 \ mq_setattr.2 \ mq_unlink.2 \ msgctl.2 \ msgget.2 \ msgrcv.2 \ msgsnd.2 \ msync.2 \ munmap.2 \ nanosleep.2 \ nfssvc.2 \ ntp_adjtime.2 \ open.2 \ pathconf.2 \ pdfork.2 \ pipe.2 \ poll.2 \ posix_fadvise.2 \ posix_fallocate.2 \ posix_openpt.2 \ procctl.2 \ profil.2 \ pselect.2 \ ptrace.2 \ quotactl.2 \ rctl_add_rule.2 \ read.2 \ readlink.2 \ reboot.2 \ recv.2 \ rename.2 \ revoke.2 \ rfork.2 \ rmdir.2 \ rtprio.2 \ sched_get_priority_max.2 \ sched_setparam.2 \ sched_setscheduler.2 \ sched_yield.2 \ sctp_generic_recvmsg.2 \ sctp_generic_sendmsg.2 \ sctp_peeloff.2 \ select.2 \ semctl.2 \ semget.2 \ semop.2 \ send.2 \ setfib.2 \ sendfile.2 \ setgroups.2 \ setpgid.2 \ setregid.2 \ setresuid.2 \ setreuid.2 \ setsid.2 \ setuid.2 \ shmat.2 \ shmctl.2 \ shmget.2 \ shm_open.2 \ shutdown.2 \ sigaction.2 \ sigaltstack.2 \ sigfastblock.2 \ sigpending.2 \ sigprocmask.2 \ sigqueue.2 \ sigreturn.2 \ sigstack.2 \ sigsuspend.2 \ sigwait.2 \ sigwaitinfo.2 \ socket.2 \ socketpair.2 \ stat.2 \ statfs.2 \ swapon.2 \ symlink.2 \ sync.2 \ sysarch.2 \ syscall.2 \ thr_exit.2 \ thr_kill.2 \ thr_new.2 \ thr_self.2 \ thr_set_name.2 \ thr_suspend.2 \ thr_wake.2 \ timer_create.2 \ timer_delete.2 \ timer_settime.2 \ truncate.2 \ umask.2 \ undelete.2 \ unlink.2 \ utimensat.2 \ utimes.2 \ utrace.2 \ uuidgen.2 \ vfork.2 \ wait.2 \ write.2 \ _umtx_op.2 MLINKS+=aio_read.2 aio_readv.2 MLINKS+=aio_write.2 aio_writev.2 MLINKS+=accept.2 accept4.2 MLINKS+=access.2 eaccess.2 \ access.2 faccessat.2 MLINKS+=brk.2 sbrk.2 MLINKS+=cap_enter.2 cap_getmode.2 MLINKS+=cap_fcntls_limit.2 cap_fcntls_get.2 MLINKS+=cap_ioctls_limit.2 cap_ioctls_get.2 MLINKS+=chdir.2 fchdir.2 MLINKS+=chflags.2 chflagsat.2 \ chflags.2 fchflags.2 \ chflags.2 lchflags.2 MLINKS+=chmod.2 fchmod.2 \ chmod.2 fchmodat.2 \ chmod.2 lchmod.2 MLINKS+=chown.2 fchown.2 \ chown.2 fchownat.2 \ chown.2 lchown.2 MLINKS+=clock_gettime.2 clock_getres.2 \ clock_gettime.2 clock_settime.2 MLINKS+=closefrom.2 close_range.2 MLINKS+=nanosleep.2 clock_nanosleep.2 MLINKS+=cpuset.2 cpuset_getid.2 \ cpuset.2 cpuset_setid.2 MLINKS+=cpuset_getaffinity.2 cpuset_setaffinity.2 MLINKS+=cpuset_getdomain.2 cpuset_setdomain.2 MLINKS+=dup.2 dup2.2 MLINKS+=eventfd.2 eventfd_read.3 \ eventfd.2 eventfd_write.3 MLINKS+=execve.2 fexecve.2 MLINKS+=extattr_get_file.2 extattr.2 \ extattr_get_file.2 extattr_delete_fd.2 \ extattr_get_file.2 extattr_delete_file.2 \ extattr_get_file.2 extattr_delete_link.2 \ extattr_get_file.2 extattr_get_fd.2 \ extattr_get_file.2 extattr_get_link.2 \ extattr_get_file.2 extattr_list_fd.2 \ extattr_get_file.2 extattr_list_file.2 \ extattr_get_file.2 extattr_list_link.2 \ extattr_get_file.2 extattr_set_fd.2 \ extattr_get_file.2 extattr_set_file.2 \ extattr_get_file.2 extattr_set_link.2 MLINKS+=ffclock.2 ffclock_getcounter.2 \ ffclock.2 ffclock_getestimate.2 \ ffclock.2 ffclock_setestimate.2 MLINKS+=fhlink.2 fhlinkat.2 MLINKS+=fhopen.2 fhstat.2 fhopen.2 fhstatfs.2 MLINKS+=fsync.2 fdatasync.2 MLINKS+=getdirentries.2 getdents.2 MLINKS+=getfh.2 lgetfh.2 \ getfh.2 getfhat.2 MLINKS+=getgid.2 getegid.2 MLINKS+=getitimer.2 setitimer.2 MLINKS+=getlogin.2 getlogin_r.3 MLINKS+=getlogin.2 setlogin.2 MLINKS+=getloginclass.2 setloginclass.2 MLINKS+=getpgrp.2 getpgid.2 MLINKS+=getpid.2 getppid.2 MLINKS+=getpriority.2 setpriority.2 MLINKS+=getrlimit.2 setrlimit.2 MLINKS+=getsockopt.2 setsockopt.2 MLINKS+=gettimeofday.2 settimeofday.2 MLINKS+=getuid.2 geteuid.2 MLINKS+=intro.2 errno.2 MLINKS+=jail.2 jail_attach.2 \ jail.2 jail_get.2 \ jail.2 jail_remove.2 \ jail.2 jail_set.2 MLINKS+=kldunload.2 kldunloadf.2 MLINKS+=kqueue.2 kevent.2 \ - kqueue.2 kqueue1.2 \ + kqueue.2 kqueuex.2 \ kqueue.2 EV_SET.3 MLINKS+=link.2 linkat.2 MLINKS+=madvise.2 posix_madvise.2 MLINKS+=mkdir.2 mkdirat.2 MLINKS+=mkfifo.2 mkfifoat.2 MLINKS+=mknod.2 mknodat.2 MLINKS+=mlock.2 munlock.2 MLINKS+=mlockall.2 munlockall.2 MLINKS+=modnext.2 modfnext.2 MLINKS+=mount.2 nmount.2 \ mount.2 unmount.2 MLINKS+=mq_receive.2 mq_timedreceive.2 MLINKS+=mq_send.2 mq_timedsend.2 MLINKS+=ntp_adjtime.2 ntp_gettime.2 MLINKS+=open.2 openat.2 MLINKS+=pathconf.2 fpathconf.2 MLINKS+=pathconf.2 lpathconf.2 MLINKS+=pdfork.2 pdgetpid.2\ pdfork.2 pdkill.2 MLINKS+=pipe.2 pipe2.2 MLINKS+=poll.2 ppoll.2 MLINKS+=rctl_add_rule.2 rctl_get_limits.2 \ rctl_add_rule.2 rctl_get_racct.2 \ rctl_add_rule.2 rctl_get_rules.2 \ rctl_add_rule.2 rctl_remove_rule.2 MLINKS+=read.2 pread.2 \ read.2 preadv.2 \ read.2 readv.2 MLINKS+=readlink.2 readlinkat.2 MLINKS+=recv.2 recvfrom.2 \ recv.2 recvmsg.2 MLINKS+=rename.2 renameat.2 MLINKS+=rtprio.2 rtprio_thread.2 MLINKS+=sched_get_priority_max.2 sched_get_priority_min.2 \ sched_get_priority_max.2 sched_rr_get_interval.2 MLINKS+=sched_setparam.2 sched_getparam.2 MLINKS+=sched_setscheduler.2 sched_getscheduler.2 MLINKS+=select.2 FD_CLR.3 \ select.2 FD_ISSET.3 \ select.2 FD_SET.3 \ select.2 FD_ZERO.3 MLINKS+=send.2 sendmsg.2 \ send.2 sendto.2 MLINKS+=setpgid.2 setpgrp.2 MLINKS+=setresuid.2 getresgid.2 \ setresuid.2 getresuid.2 \ setresuid.2 setresgid.2 MLINKS+=setuid.2 setegid.2 \ setuid.2 seteuid.2 \ setuid.2 setgid.2 MLINKS+=shmat.2 shmdt.2 MLINKS+=shm_open.2 memfd_create.3 \ shm_open.2 shm_create_largepage.3 \ shm_open.2 shm_unlink.2 \ shm_open.2 shm_rename.2 MLINKS+=sigwaitinfo.2 sigtimedwait.2 MLINKS+=stat.2 fstat.2 \ stat.2 fstatat.2 \ stat.2 lstat.2 MLINKS+=statfs.2 fstatfs.2 MLINKS+=swapon.2 swapoff.2 MLINKS+=symlink.2 symlinkat.2 MLINKS+=syscall.2 __syscall.2 MLINKS+=timer_settime.2 timer_getoverrun.2 \ timer_settime.2 timer_gettime.2 MLINKS+=thr_kill.2 thr_kill2.2 MLINKS+=truncate.2 ftruncate.2 MLINKS+=unlink.2 unlinkat.2 MLINKS+=unlink.2 funlinkat.2 MLINKS+=utimensat.2 futimens.2 MLINKS+=utimes.2 futimes.2 \ utimes.2 futimesat.2 \ utimes.2 lutimes.2 MLINKS+=wait.2 wait3.2 \ wait.2 wait4.2 \ wait.2 waitpid.2 \ wait.2 waitid.2 \ wait.2 wait6.2 MLINKS+=write.2 pwrite.2 \ write.2 pwritev.2 \ write.2 writev.2 diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index 7f6afd7b298b..cc90998e83fb 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -1,1052 +1,1052 @@ /* * $FreeBSD$ */ /* * It'd be nice to automatically generate the syscall symbols, but we * don't know to what version they will eventually belong to, so for now * it has to be manual. */ FBSD_1.0 { __acl_aclcheck_fd; __acl_aclcheck_file; __acl_aclcheck_link; __acl_delete_fd; __acl_delete_file; __acl_delete_link; __acl_get_fd; __acl_get_file; __acl_get_link; __acl_set_fd; __acl_set_file; __acl_set_link; __getcwd; __mac_execve; __mac_get_fd; __mac_get_file; __mac_get_link; __mac_get_pid; __mac_get_proc; __mac_set_fd; __mac_set_file; __mac_set_link; __mac_set_proc; __setugid; __syscall; __sysctl; _umtx_op; abort2; accept; access; acct; adjtime; aio_cancel; aio_error; aio_fsync; aio_read; aio_return; aio_suspend; aio_waitcomplete; aio_write; audit; auditctl; auditon; bind; chdir; chflags; chmod; chown; chroot; clock_getres; clock_gettime; clock_settime; close; connect; dup; dup2; eaccess; execve; extattr_delete_fd; extattr_delete_file; extattr_delete_link; extattr_get_fd; extattr_get_file; extattr_get_link; extattr_list_fd; extattr_list_file; extattr_list_link; extattr_set_fd; extattr_set_file; extattr_set_link; extattrctl; fchdir; fchflags; fchmod; fchown; fcntl; fhopen; flock; fork; fpathconf; fsync; futimes; getaudit; getaudit_addr; getauid; getcontext; getdtablesize; getegid; geteuid; getfh; getgid; getgroups; getitimer; getpeername; getpgid; getpgrp; getpid; getppid; getpriority; getresgid; getresuid; getrlimit; getrusage; getsid; getsockname; getsockopt; gettimeofday; getuid; ioctl; issetugid; jail; jail_attach; kenv; kill; kldfind; kldfirstmod; kldload; kldnext; kldstat; kldsym; kldunload; kldunloadf; kqueue; kmq_notify; /* Do we want these to be public interfaces? */ kmq_open; /* librt uses them to provide mq_xxx. */ kmq_setattr; kmq_timedreceive; kmq_timedsend; kmq_unlink; ksem_close; ksem_destroy; ksem_getvalue; ksem_init; ksem_open; ksem_post; ksem_timedwait; ksem_trywait; ksem_unlink; ksem_wait; ktrace; lchflags; lchmod; lchown; lgetfh; link; lio_listio; listen; lutimes; mac_syscall; madvise; mincore; minherit; mkdir; mkfifo; mlock; mlockall; modfind; modfnext; modnext; modstat; mount; mprotect; msgget; msgrcv; msgsnd; msgsys; msync; munlock; munlockall; munmap; nanosleep; nfssvc; nmount; ntp_adjtime; ntp_gettime; open; pathconf; pipe; poll; posix_openpt; preadv; profil; pselect; ptrace; pwritev; quotactl; read; readlink; readv; reboot; recvfrom; recvmsg; rename; revoke; rfork; rmdir; rtprio; rtprio_thread; sched_get_priority_max; sched_get_priority_min; sched_getparam; sched_getscheduler; sched_rr_get_interval; sched_setparam; sched_setscheduler; sched_yield; select; semget; semop; semsys; sendfile; sendmsg; sendto; setaudit; setaudit_addr; setauid; setegid; seteuid; setgid; setgroups; setitimer; setlogin; setpgid; setpriority; setregid; setresgid; setresuid; setreuid; setrlimit; setsid; setsockopt; settimeofday; setuid; shm_open; shm_unlink; shmat; shmdt; shmget; shmsys; shutdown; sigaction; sigaltstack; sigpending; sigprocmask; sigqueue; sigreturn; sigsuspend; sigtimedwait; sigwait; sigwaitinfo; socket; socketpair; swapon; symlink; sync; sysarch; syscall; thr_create; thr_exit; thr_kill; thr_kill2; thr_new; thr_self; thr_set_name; thr_suspend; thr_wake; ktimer_create; /* Do we want these to be public interfaces? */ ktimer_delete; /* librt uses them to provide timer_xxx. */ ktimer_getoverrun; ktimer_gettime; ktimer_settime; umask; undelete; unlink; unmount; utimes; utrace; uuidgen; vadvise; wait4; write; writev; __error; ftruncate; lseek; mmap; pread; pwrite; truncate; }; FBSD_1.1 { __semctl; closefrom; cpuset; cpuset_getid; cpuset_setid; cpuset_getaffinity; cpuset_setaffinity; faccessat; fchmodat; fchownat; fexecve; futimesat; jail_get; jail_set; jail_remove; linkat; lpathconf; mkdirat; mkfifoat; msgctl; readlinkat; renameat; setfib; shmctl; symlinkat; unlinkat; }; FBSD_1.2 { cap_enter; cap_getmode; getloginclass; pdfork; pdgetpid; pdkill; posix_fallocate; rctl_get_racct; rctl_get_rules; rctl_get_limits; rctl_add_rule; rctl_remove_rule; setloginclass; }; FBSD_1.3 { accept4; aio_mlock; bindat; cap_fcntls_get; cap_fcntls_limit; cap_ioctls_get; cap_ioctls_limit; __cap_rights_get; cap_rights_limit; cap_sandboxed; chflagsat; clock_getcpuclockid2; connectat; ffclock_getcounter; ffclock_getestimate; ffclock_setestimate; pipe2; posix_fadvise; procctl; wait6; }; FBSD_1.4 { futimens; ppoll; utimensat; numa_setaffinity; numa_getaffinity; sendmmsg; recvmmsg; }; FBSD_1.5 { clock_nanosleep; fdatasync; fhstat; fhstatfs; fstat; fstatat; fstatfs; getdents; getdirentries; getfsstat; getrandom; kevent; lstat; mknod; mknodat; stat; statfs; cpuset_getdomain; cpuset_setdomain; }; FBSD_1.6 { __sysctlbyname; aio_readv; aio_writev; close_range; copy_file_range; fhlink; fhlinkat; fhreadlink; getfhat; funlinkat; memfd_create; shm_create_largepage; shm_rename; }; FBSD_1.7 { _Fork; fspacectl; - kqueue1; + kqueuex; swapoff; }; FBSDprivate_1.0 { ___acl_aclcheck_fd; __sys___acl_aclcheck_fd; ___acl_aclcheck_file; __sys___acl_aclcheck_file; ___acl_aclcheck_link; __sys___acl_aclcheck_link; ___acl_delete_fd; __sys___acl_delete_fd; ___acl_delete_file; __sys___acl_delete_file; ___acl_delete_link; __sys___acl_delete_link; ___acl_get_fd; __sys___acl_get_fd; ___acl_get_file; __sys___acl_get_file; ___acl_get_link; __sys___acl_get_link; ___acl_set_fd; __sys___acl_set_fd; ___acl_set_file; __sys___acl_set_file; ___acl_set_link; __sys___acl_set_link; ___getcwd; __sys___getcwd; ___mac_execve; __sys___mac_execve; ___mac_get_fd; __sys___mac_get_fd; ___mac_get_file; __sys___mac_get_file; ___mac_get_link; __sys___mac_get_link; ___mac_get_pid; __sys___mac_get_pid; ___mac_get_proc; __sys___mac_get_proc; ___mac_set_fd; __sys___mac_set_fd; ___mac_set_file; __sys___mac_set_file; ___mac_set_link; __sys___mac_set_link; ___mac_set_proc; __sys___mac_set_proc; ___semctl; __sys___semctl; ___setugid; __sys___setugid; ___syscall; __sys___syscall; ___sysctl; __sys___sysctl; __umtx_op; __sys__umtx_op; _abort2; __sys_abort2; _accept; __sys_accept; _accept4; __sys_accept4; _access; __sys_access; _acct; __sys_acct; _adjtime; __sys_adjtime; __sys_aio_cancel; __sys_aio_error; __sys_aio_fsync; __sys_aio_read; __sys_aio_readv; __sys_aio_return; __sys_aio_suspend; __sys_aio_waitcomplete; __sys_aio_write; __sys_aio_writev; _audit; __sys_audit; _auditctl; __sys_auditctl; _auditon; __sys_auditon; _bind; __sys_bind; _chdir; __sys_chdir; _chflags; __sys_chflags; _chmod; __sys_chmod; _chown; __sys_chown; _chroot; __sys_chroot; _clock_getcpuclockid2; __sys_clock_getcpuclockid2; _clock_getres; __sys_clock_getres; _clock_gettime; __sys_clock_gettime; __sys_clock_nanosleep; _clock_settime; __sys_clock_settime; _close; __sys_close; _connect; __sys_connect; _cpuset; __sys_cpuset; _cpuset_getid; __sys_cpuset_getid; _cpuset_setid; __sys_cpuset_setid; _cpuset_getaffinity; __sys_cpuset_getaffinity; _cpuset_setaffinity; __sys_cpuset_setaffinity; _dup; __sys_dup; _dup2; __sys_dup2; _eaccess; __sys_eaccess; _execve; __sys_execve; _extattr_delete_fd; __sys_extattr_delete_fd; _extattr_delete_file; __sys_extattr_delete_file; _extattr_delete_link; __sys_extattr_delete_link; _extattr_get_fd; __sys_extattr_get_fd; _extattr_get_file; __sys_extattr_get_file; _extattr_get_link; __sys_extattr_get_link; _extattr_list_fd; __sys_extattr_list_fd; _extattr_list_file; __sys_extattr_list_file; _extattr_list_link; __sys_extattr_list_link; _extattr_set_fd; __sys_extattr_set_fd; _extattr_set_file; __sys_extattr_set_file; _extattr_set_link; __sys_extattr_set_link; _extattrctl; __sys_extattrctl; __sys_sigfastblock; _fchdir; __sys_fchdir; _fchflags; __sys_fchflags; _fchmod; __sys_fchmod; _fchown; __sys_fchown; _fcntl; __sys_fcntl; __fcntl_compat; _fhopen; __sys_fhopen; _fhstat; __sys_fhstat; _fhstatfs; __sys_fhstatfs; _flock; __sys_flock; _fork; __sys_fork; _fpathconf; __sys_fpathconf; _fstat; __sys_fstat; _fstatfs; __sys_fstatfs; _fsync; __sys_fsync; _fdatasync; __sys_fdatasync; _futimes; __sys_futimes; _getaudit; __sys_getaudit; _getaudit_addr; __sys_getaudit_addr; _getauid; __sys_getauid; _getcontext; __sys_getcontext; _getdirentries; __sys_getdirentries; _getdtablesize; __sys_getdtablesize; _getegid; __sys_getegid; _geteuid; __sys_geteuid; _getfh; __sys_getfh; _getfsstat; __sys_getfsstat; _getgid; __sys_getgid; _getgroups; __sys_getgroups; _getitimer; __sys_getitimer; _getpeername; __sys_getpeername; _getpgid; __sys_getpgid; _getpgrp; __sys_getpgrp; _getpid; __sys_getpid; _getppid; __sys_getppid; _getpriority; __sys_getpriority; _getresgid; __sys_getresgid; _getresuid; __sys_getresuid; _getrlimit; __sys_getrlimit; _getrusage; __sys_getrusage; _getsid; __sys_getsid; _getsockname; __sys_getsockname; _getsockopt; __sys_getsockopt; _gettimeofday; __sys_gettimeofday; _getuid; __sys_getuid; _ioctl; __sys_ioctl; _issetugid; __sys_issetugid; _jail; __sys_jail; _jail_attach; __sys_jail_attach; _kenv; __sys_kenv; _kevent; __sys_kevent; _kill; __sys_kill; _kldfind; __sys_kldfind; _kldfirstmod; __sys_kldfirstmod; _kldload; __sys_kldload; _kldnext; __sys_kldnext; _kldstat; __sys_kldstat; _kldsym; __sys_kldsym; _kldunload; __sys_kldunload; _kldunloadf; __sys_kldunloadf; _kmq_notify; __sys_kmq_notify; _kmq_open; __sys_kmq_open; _kmq_setattr; __sys_kmq_setattr; _kmq_timedreceive; __sys_kmq_timedreceive; _kmq_timedsend; __sys_kmq_timedsend; _kmq_unlink; __sys_kmq_unlink; _kqueue; __sys_kqueue; _ksem_close; __sys_ksem_close; _ksem_destroy; __sys_ksem_destroy; _ksem_getvalue; __sys_ksem_getvalue; _ksem_init; __sys_ksem_init; _ksem_open; __sys_ksem_open; _ksem_post; __sys_ksem_post; _ksem_timedwait; __sys_ksem_timedwait; _ksem_trywait; __sys_ksem_trywait; _ksem_unlink; __sys_ksem_unlink; _ksem_wait; __sys_ksem_wait; _ktrace; __sys_ktrace; _lchflags; __sys_lchflags; _lchmod; __sys_lchmod; _lchown; __sys_lchown; _lgetfh; __sys_lgetfh; _link; __sys_link; __sys_lio_listio; _listen; __sys_listen; _lutimes; __sys_lutimes; _mac_syscall; __sys_mac_syscall; _madvise; __sys_madvise; _mincore; __sys_mincore; _minherit; __sys_minherit; _mkdir; __sys_mkdir; _mkfifo; __sys_mkfifo; _mknod; __sys_mknod; _mlock; __sys_mlock; _mlockall; __sys_mlockall; _mmap; __sys_mmap; _modfind; __sys_modfind; _modfnext; __sys_modfnext; _modnext; __sys_modnext; _modstat; __sys_modstat; _mount; __sys_mount; _mprotect; __sys_mprotect; _msgctl; __sys_msgctl; _msgget; __sys_msgget; _msgrcv; __sys_msgrcv; _msgsnd; __sys_msgsnd; _msgsys; __sys_msgsys; _msync; __sys_msync; _munlock; __sys_munlock; _munlockall; __sys_munlockall; _munmap; __sys_munmap; _nanosleep; __sys_nanosleep; _nfssvc; __sys_nfssvc; _nmount; __sys_nmount; _ntp_adjtime; __sys_ntp_adjtime; _ntp_gettime; __sys_ntp_gettime; _open; __sys_open; _openat; __sys_openat; _pathconf; __sys_pathconf; __sys_pdfork; _pipe; __sys_pipe; _poll; __sys_poll; _ppoll; __sys_ppoll; _preadv; __sys_preadv; _procctl; __sys_procctl; _profil; __sys_profil; _pselect; __sys_pselect; _ptrace; __sys_ptrace; _pwritev; __sys_pwritev; _quotactl; __sys_quotactl; _read; __sys_read; _readlink; __sys_readlink; _readv; __sys_readv; _reboot; __sys_reboot; _recvfrom; __sys_recvfrom; _recvmsg; __sys_recvmsg; _rename; __sys_rename; _revoke; __sys_revoke; _rfork; __sys_rfork; _rmdir; __sys_rmdir; _rtprio; __sys_rtprio; _rtprio_thread; __sys_rtprio_thread; _sched_get_priority_max; __sys_sched_get_priority_max; _sched_get_priority_min; __sys_sched_get_priority_min; _sched_getparam; __sys_sched_getparam; _sched_getscheduler; __sys_sched_getscheduler; _sched_rr_get_interval; __sys_sched_rr_get_interval; _sched_setparam; __sys_sched_setparam; _sched_setscheduler; __sys_sched_setscheduler; _sched_yield; __sys_sched_yield; _select; __sys_select; _semget; __sys_semget; _semop; __sys_semop; _semsys; __sys_semsys; _sendfile; __sys_sendfile; _sendmsg; __sys_sendmsg; _sendto; __sys_sendto; _setaudit; __sys_setaudit; _setaudit_addr; __sys_setaudit_addr; _setauid; __sys_setauid; _setcontext; __sys_setcontext; _setegid; __sys_setegid; _seteuid; __sys_seteuid; _setgid; __sys_setgid; _setgroups; __sys_setgroups; _setitimer; __sys_setitimer; _setlogin; __sys_setlogin; _setpgid; __sys_setpgid; _setpriority; __sys_setpriority; _setregid; __sys_setregid; _setresgid; __sys_setresgid; _setresuid; __sys_setresuid; _setreuid; __sys_setreuid; _setrlimit; __sys_setrlimit; _setsid; __sys_setsid; _setsockopt; __sys_setsockopt; _settimeofday; __sys_settimeofday; _setuid; __sys_setuid; _shm_open; __sys_shm_open; __sys_shm_open2; _shm_unlink; __sys_shm_unlink; _shmat; __sys_shmat; _shmctl; __sys_shmctl; _shmdt; __sys_shmdt; _shmget; __sys_shmget; _shmsys; __sys_shmsys; _shutdown; __sys_shutdown; _sigaction; __sys_sigaction; _sigaltstack; __sys_sigaltstack; _sigpending; __sys_sigpending; _sigprocmask; __sys_sigprocmask; _sigqueue; __sys_sigqueue; _sigreturn; __sys_sigreturn; _sigsuspend; __sys_sigsuspend; _sigtimedwait; __sys_sigtimedwait; _sigwait; __sigwait; __sys_sigwait; _sigwaitinfo; __sys_sigwaitinfo; _socket; __sys_socket; _socketpair; __sys_socketpair; _statfs; __sys_statfs; _swapcontext; __sys_swapcontext; _swapoff; __sys_swapoff; _swapon; __sys_swapon; _symlink; __sys_symlink; _sync; __sys_sync; _sysarch; __sys_sysarch; _syscall; __sys_syscall; _thr_create; __sys_thr_create; _thr_exit; __sys_thr_exit; _thr_kill; __sys_thr_kill; _thr_kill2; __sys_thr_kill2; _thr_new; __sys_thr_new; _thr_self; __sys_thr_self; _thr_set_name; __sys_thr_set_name; _thr_suspend; __sys_thr_suspend; _thr_wake; __sys_thr_wake; _ktimer_create; __sys_ktimer_create; _ktimer_delete; __sys_ktimer_delete; _ktimer_getoverrun; __sys_ktimer_getoverrun; _ktimer_gettime; __sys_ktimer_gettime; _ktimer_settime; __sys_ktimer_settime; _umask; __sys_umask; _undelete; __sys_undelete; _unlink; __sys_unlink; _unmount; __sys_unmount; _utimes; __sys_utimes; _utrace; __sys_utrace; _uuidgen; __sys_uuidgen; _wait4; __sys_wait4; _wait6; __sys_wait6; _write; __sys_write; _writev; __sys_writev; __set_error_selector; nlm_syscall; gssd_syscall; __libc_interposing_slot; __libc_sigwait; _cpuset_getdomain; __sys_cpuset_getdomain; _cpuset_setdomain; __sys_cpuset_setdomain; rpctls_syscall; }; diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2 index a2470696d4df..af60bb396d6a 100644 --- a/lib/libc/sys/kqueue.2 +++ b/lib/libc/sys/kqueue.2 @@ -1,877 +1,877 @@ .\" Copyright (c) 2000 Jonathan Lemon .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd March 26, 2023 .Dt KQUEUE 2 .Os .Sh NAME .Nm kqueue , .Nm kevent .Nd kernel event notification mechanism .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/event.h .Ft int .Fn kqueue "void" .Ft int -.Fn kqueue1 "u_int flags" +.Fn kqueuex "u_int flags" .Ft int .Fo kevent .Fa "int kq" .Fa "const struct kevent *changelist" .Fa "int nchanges" .Fa "struct kevent *eventlist" .Fa "int nevents" .Fa "const struct timespec *timeout" .Fc .Fn EV_SET "kev" ident filter flags fflags data udata .Sh DESCRIPTION The .Fn kqueue system call provides a generic method of notifying the user when an event happens or a condition holds, based on the results of small pieces of kernel code termed filters. A kevent is identified by the (ident, filter) pair; there may only be one unique kevent per kqueue. .Pp The filter is executed upon the initial registration of a kevent in order to detect whether a preexisting condition is present, and is also executed whenever an event is passed to the filter for evaluation. If the filter determines that the condition should be reported, then the kevent is placed on the kqueue for the user to retrieve. .Pp The filter is also run when the user attempts to retrieve the kevent from the kqueue. If the filter indicates that the condition that triggered the event no longer holds, the kevent is removed from the kqueue and is not returned. .Pp Multiple events which trigger the filter do not result in multiple kevents being placed on the kqueue; instead, the filter will aggregate the events into a single struct kevent. Calling .Fn close on a file descriptor will remove any kevents that reference the descriptor. .Pp The .Fn kqueue system call creates a new kernel event queue and returns a descriptor. The queue is not inherited by a child created with .Xr fork 2 . However, if .Xr rfork 2 is called without the .Dv RFFDG flag, then the descriptor table is shared, which will allow sharing of the kqueue between two processes. .Pp The -.Fn kqueue1 +.Fn kqueuex system call also creates a new kernel event queue, and additionally takes the .Fa flags argument, which is a bitwise-inclusive OR of the following flags: .Bl -tag -width "KQUEUE_CLOEXEC" .It Fa KQUEUE_CLOEXEC The returned file descriptor is automatically closed on .Xr execve 2 .El The .Ql fd = kqueue() call is equivalent to -.Ql fd = kqueue1(0) . +.Ql fd = kqueuex(0) . .Pp The .Fn kevent system call is used to register events with the queue, and return any pending events to the user. The .Fa changelist argument is a pointer to an array of .Va kevent structures, as defined in .In sys/event.h . All changes contained in the .Fa changelist are applied before any pending events are read from the queue. The .Fa nchanges argument gives the size of .Fa changelist . The .Fa eventlist argument is a pointer to an array of kevent structures. The .Fa nevents argument determines the size of .Fa eventlist . When .Fa nevents is zero, .Fn kevent will return immediately even if there is a .Fa timeout specified unlike .Xr select 2 . If .Fa timeout is a non-NULL pointer, it specifies a maximum interval to wait for an event, which will be interpreted as a struct timespec. If .Fa timeout is a NULL pointer, .Fn kevent waits indefinitely. To effect a poll, the .Fa timeout argument should be non-NULL, pointing to a zero-valued .Va timespec structure. The same array may be used for the .Fa changelist and .Fa eventlist . .Pp The .Fn EV_SET macro is provided for ease of initializing a kevent structure. .Pp The .Va kevent structure is defined as: .Bd -literal struct kevent { uintptr_t ident; /* identifier for this event */ short filter; /* filter for event */ u_short flags; /* action flags for kqueue */ u_int fflags; /* filter flag value */ int64_t data; /* filter data value */ void *udata; /* opaque user data identifier */ uint64_t ext[4]; /* extensions */ }; .Ed .Pp The fields of .Fa struct kevent are: .Bl -tag -width "Fa filter" .It Fa ident Value used to identify this event. The exact interpretation is determined by the attached filter, but often is a file descriptor. .It Fa filter Identifies the kernel filter used to process this event. The pre-defined system filters are described below. .It Fa flags Actions to perform on the event. .It Fa fflags Filter-specific flags. .It Fa data Filter-specific data value. .It Fa udata Opaque user-defined value passed through the kernel unchanged. .It Fa ext Extended data passed to and from kernel. The .Fa ext[0] and .Fa ext[1] members use is defined by the filter. If the filter does not use them, the members are copied unchanged. The .Fa ext[2] and .Fa ext[3] members are always passed through the kernel as-is, making additional context available to application. .El .Pp The .Va flags field can contain the following values: .Bl -tag -width EV_DISPATCH .It Dv EV_ADD Adds the event to the kqueue. Re-adding an existing event will modify the parameters of the original event, and not result in a duplicate entry. Adding an event automatically enables it, unless overridden by the EV_DISABLE flag. .It Dv EV_ENABLE Permit .Fn kevent to return the event if it is triggered. .It Dv EV_DISABLE Disable the event so .Fn kevent will not return it. The filter itself is not disabled. .It Dv EV_DISPATCH Disable the event source immediately after delivery of an event. See .Dv EV_DISABLE above. .It Dv EV_DELETE Removes the event from the kqueue. Events which are attached to file descriptors are automatically deleted on the last close of the descriptor. .It Dv EV_RECEIPT This flag is useful for making bulk changes to a kqueue without draining any pending events. When passed as input, it forces .Dv EV_ERROR to always be returned. When a filter is successfully added the .Va data field will be zero. Note that if this flag is encountered and there is no remaining space in .Fa eventlist to hold the .Dv EV_ERROR event, then subsequent changes will not get processed. .It Dv EV_ONESHOT Causes the event to return only the first occurrence of the filter being triggered. After the user retrieves the event from the kqueue, it is deleted. .It Dv EV_CLEAR After the event is retrieved by the user, its state is reset. This is useful for filters which report state transitions instead of the current state. Note that some filters may automatically set this flag internally. .It Dv EV_EOF Filters may set this flag to indicate filter-specific EOF condition. .It Dv EV_ERROR See .Sx RETURN VALUES below. .It Dv EV_KEEPUDATA Causes .Fn kevent to leave unchanged any .Fa udata associated with an existing event. This allows other aspects of the event to be modified without requiring the caller to know the .Fa udata value presently associated. This is especially useful with .Dv NOTE_TRIGGER or flags like .Dv EV_ENABLE . This flag may not be used with .Dv EV_ADD . .El .Pp The predefined system filters are listed below. Arguments may be passed to and from the filter via the .Va fflags and .Va data fields in the kevent structure. .Bl -tag -width "Dv EVFILT_PROCDESC" .It Dv EVFILT_READ Takes a descriptor as the identifier, and returns whenever there is data available to read. The behavior of the filter is slightly different depending on the descriptor type. .Bl -tag -width 2n .It Sockets Sockets which have previously been passed to .Xr listen 2 return when there is an incoming connection pending. .Va data contains the size of the listen backlog. .Pp Other socket descriptors return when there is data to be read, subject to the .Dv SO_RCVLOWAT value of the socket buffer. This may be overridden with a per-filter low water mark at the time the filter is added by setting the .Dv NOTE_LOWAT flag in .Va fflags , and specifying the new low water mark in .Va data . On return, .Va data contains the number of bytes of protocol data available to read. .Pp If the read direction of the socket has shutdown, then the filter also sets .Dv EV_EOF in .Va flags , and returns the socket error (if any) in .Va fflags . It is possible for EOF to be returned (indicating the connection is gone) while there is still data pending in the socket buffer. .It Vnodes Returns when the file pointer is not at the end of file. .Va data contains the offset from current position to end of file, and may be negative. .Pp This behavior is different from .Xr poll 2 , where read events are triggered for regular files unconditionally. This event can be triggered unconditionally by setting the .Dv NOTE_FILE_POLL flag in .Va fflags . .It "Fifos, Pipes" Returns when the there is data to read; .Va data contains the number of bytes available. .Pp When the last writer disconnects, the filter will set .Dv EV_EOF in .Va flags . This will be cleared by the filter when a new writer connects, at which point the filter will resume waiting for data to become available before returning. .It "BPF devices" Returns when the BPF buffer is full, the BPF timeout has expired, or when the BPF has .Dq immediate mode enabled and there is any data to read; .Va data contains the number of bytes available. .It Eventfds Returns when the counter is greater than 0; .Va data contains the counter value, which must be cast to .Vt uint64_t . .It Kqueues Returns when pending events are present on the queue; .Va data contains the number of events available. .El .It Dv EVFILT_WRITE Takes a descriptor as the identifier, and returns whenever it is possible to write to the descriptor. For sockets, pipes and fifos, .Va data will contain the amount of space remaining in the write buffer. The filter will set .Dv EV_EOF when the reader disconnects, and for the fifo case, this will be cleared when a new reader connects. Note that this filter is not supported for vnodes. .Pp For sockets, the low water mark and socket error handling is identical to the .Dv EVFILT_READ case. .Pp For eventfds, .Va data will contain the maximum value that can be added to the counter without blocking. .Pp For BPF devices, when the descriptor is attached to an interface the filter always indicates that it is possible to write and .Va data will contain the MTU size of the underlying interface. .It Dv EVFILT_EMPTY Takes a descriptor as the identifier, and returns whenever there is no remaining data in the write buffer. .It Dv EVFILT_AIO Events for this filter are not registered with .Fn kevent directly but are registered via the .Va aio_sigevent member of an asynchronous I/O request when it is scheduled via an asynchronous I/O system call such as .Fn aio_read . The filter returns under the same conditions as .Fn aio_error . For more details on this filter see .Xr sigevent 3 and .Xr aio 4 . .It Dv EVFILT_VNODE Takes a file descriptor as the identifier and the events to watch for in .Va fflags , and returns when one or more of the requested events occurs on the descriptor. The events to monitor are: .Bl -tag -width "Dv NOTE_CLOSE_WRITE" .It Dv NOTE_ATTRIB The file referenced by the descriptor had its attributes changed. .It Dv NOTE_CLOSE A file descriptor referencing the monitored file, was closed. The closed file descriptor did not have write access. .It Dv NOTE_CLOSE_WRITE A file descriptor referencing the monitored file, was closed. The closed file descriptor had write access. .Pp This note, as well as .Dv NOTE_CLOSE , are not activated when files are closed forcibly by .Xr unmount 2 or .Xr revoke 2 . Instead, .Dv NOTE_REVOKE is sent for such events. .It Dv NOTE_DELETE The .Fn unlink system call was called on the file referenced by the descriptor. .It Dv NOTE_EXTEND For regular file, the file referenced by the descriptor was extended. .Pp For directory, reports that a directory entry was added or removed, as the result of rename operation. The .Dv NOTE_EXTEND event is not reported when a name is changed inside the directory. .It Dv NOTE_LINK The link count on the file changed. In particular, the .Dv NOTE_LINK event is reported if a subdirectory was created or deleted inside the directory referenced by the descriptor. .It Dv NOTE_OPEN The file referenced by the descriptor was opened. .It Dv NOTE_READ A read occurred on the file referenced by the descriptor. .It Dv NOTE_RENAME The file referenced by the descriptor was renamed. .It Dv NOTE_REVOKE Access to the file was revoked via .Xr revoke 2 or the underlying file system was unmounted. .It Dv NOTE_WRITE A write occurred on the file referenced by the descriptor. .El .Pp On return, .Va fflags contains the events which triggered the filter. .It Dv EVFILT_PROC Takes the process ID to monitor as the identifier and the events to watch for in .Va fflags , and returns when the process performs one or more of the requested events. If a process can normally see another process, it can attach an event to it. The events to monitor are: .Bl -tag -width "Dv NOTE_TRACKERR" .It Dv NOTE_EXIT The process has exited. The exit status will be stored in .Va data in the same format as the status returned by .Xr wait 2 . .It Dv NOTE_FORK The process has called .Fn fork . .It Dv NOTE_EXEC The process has executed a new process via .Xr execve 2 or a similar call. .It Dv NOTE_TRACK Follow a process across .Fn fork calls. The parent process registers a new kevent to monitor the child process using the same .Va fflags as the original event. The child process will signal an event with .Dv NOTE_CHILD set in .Va fflags and the parent PID in .Va data . .Pp If the parent process fails to register a new kevent .Pq usually due to resource limitations , it will signal an event with .Dv NOTE_TRACKERR set in .Va fflags , and the child process will not signal a .Dv NOTE_CHILD event. .El .Pp On return, .Va fflags contains the events which triggered the filter. .It Dv EVFILT_PROCDESC Takes the process descriptor created by .Xr pdfork 2 to monitor as the identifier and the events to watch for in .Va fflags , and returns when the associated process performs one or more of the requested events. The events to monitor are: .Bl -tag -width "Dv NOTE_EXIT" .It Dv NOTE_EXIT The process has exited. The exit status will be stored in .Va data . .El .Pp On return, .Va fflags contains the events which triggered the filter. .It Dv EVFILT_SIGNAL Takes the signal number to monitor as the identifier and returns when the given signal is delivered to the process. This coexists with the .Fn signal and .Fn sigaction facilities, and has a lower precedence. The filter will record all attempts to deliver a signal to a process, even if the signal has been marked as .Dv SIG_IGN , except for the .Dv SIGCHLD signal, which, if ignored, will not be recorded by the filter. Event notification happens after normal signal delivery processing. .Va data returns the number of times the signal has occurred since the last call to .Fn kevent . This filter automatically sets the .Dv EV_CLEAR flag internally. .It Dv EVFILT_TIMER Establishes an arbitrary timer identified by .Va ident . When adding a timer, .Va data specifies the moment to fire the timer (for .Dv NOTE_ABSTIME ) or the timeout period. The timer will be periodic unless .Dv EV_ONESHOT or .Dv NOTE_ABSTIME is specified. On return, .Va data contains the number of times the timeout has expired since the last call to .Fn kevent . For non-monotonic timers, this filter automatically sets the .Dv EV_CLEAR flag internally. .Pp The filter accepts the following flags in the .Va fflags argument: .Bl -tag -width "Dv NOTE_MSECONDS" .It Dv NOTE_SECONDS .Va data is in seconds. .It Dv NOTE_MSECONDS .Va data is in milliseconds. .It Dv NOTE_USECONDS .Va data is in microseconds. .It Dv NOTE_NSECONDS .Va data is in nanoseconds. .It Dv NOTE_ABSTIME The specified expiration time is absolute. .El .Pp If .Va fflags is not set, the default is milliseconds. On return, .Va fflags contains the events which triggered the filter. .Pp Periodic timers with a specified timeout of 0 will be silently adjusted to timeout after 1 of the time units specified by the requested precision in .Va fflags . If an absolute time is specified that has already passed, then it is treated as if the current time were specified and the event will fire as soon as possible. .Pp If an existing timer is re-added, the existing timer will be effectively canceled (throwing away any undelivered record of previous timer expiration) and re-started using the new parameters contained in .Va data and .Va fflags . .Pp There is a system wide limit on the number of timers which is controlled by the .Va kern.kq_calloutmax sysctl. .It Dv EVFILT_USER Establishes a user event identified by .Va ident which is not associated with any kernel mechanism but is triggered by user level code. The lower 24 bits of the .Va fflags may be used for user defined flags and manipulated using the following: .Bl -tag -width "Dv NOTE_FFLAGSMASK" .It Dv NOTE_FFNOP Ignore the input .Va fflags . .It Dv NOTE_FFAND Bitwise AND .Va fflags . .It Dv NOTE_FFOR Bitwise OR .Va fflags . .It Dv NOTE_FFCOPY Copy .Va fflags . .It Dv NOTE_FFCTRLMASK Control mask for .Va fflags . .It Dv NOTE_FFLAGSMASK User defined flag mask for .Va fflags . .El .Pp A user event is triggered for output with the following: .Bl -tag -width "Dv NOTE_FFLAGSMASK" .It Dv NOTE_TRIGGER Cause the event to be triggered. .El .Pp On return, .Va fflags contains the users defined flags in the lower 24 bits. .El .Sh CANCELLATION BEHAVIOUR If .Fa nevents is non-zero, i.e., the function is potentially blocking, the call is a cancellation point. Otherwise, i.e., if .Fa nevents is zero, the call is not cancellable. Cancellation can only occur before any changes are made to the kqueue, or when the call was blocked and no changes to the queue were requested. .Sh RETURN VALUES The .Fn kqueue system call creates a new kernel event queue and returns a file descriptor. If there was an error creating the kernel event queue, a value of -1 is returned and errno set. .Pp The .Fn kevent system call returns the number of events placed in the .Fa eventlist , up to the value given by .Fa nevents . If an error occurs while processing an element of the .Fa changelist and there is enough room in the .Fa eventlist , then the event will be placed in the .Fa eventlist with .Dv EV_ERROR set in .Va flags and the system error in .Va data . Otherwise, .Dv -1 will be returned, and .Dv errno will be set to indicate the error condition. If the time limit expires, then .Fn kevent returns 0. .Sh EXAMPLES .Bd -literal -compact #include #include #include #include #include #include int main(int argc, char **argv) { struct kevent event; /* Event we want to monitor */ struct kevent tevent; /* Event triggered */ int kq, fd, ret; if (argc != 2) err(EXIT_FAILURE, "Usage: %s path\en", argv[0]); fd = open(argv[1], O_RDONLY); if (fd == -1) err(EXIT_FAILURE, "Failed to open '%s'", argv[1]); /* Create kqueue. */ kq = kqueue(); if (kq == -1) err(EXIT_FAILURE, "kqueue() failed"); /* Initialize kevent structure. */ EV_SET(&event, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, NULL); /* Attach event to the kqueue. */ ret = kevent(kq, &event, 1, NULL, 0, NULL); if (ret == -1) err(EXIT_FAILURE, "kevent register"); for (;;) { /* Sleep until something happens. */ ret = kevent(kq, NULL, 0, &tevent, 1, NULL); if (ret == -1) { err(EXIT_FAILURE, "kevent wait"); } else if (ret > 0) { if (tevent.flags & EV_ERROR) errx(EXIT_FAILURE, "Event error: %s", strerror(event.data)); else printf("Something was written in '%s'\en", argv[1]); } } } .Ed .Sh ERRORS The .Fn kqueue system call fails if: .Bl -tag -width Er .It Bq Er ENOMEM The kernel failed to allocate enough memory for the kernel queue. .It Bq Er ENOMEM The .Dv RLIMIT_KQUEUES rlimit (see .Xr getrlimit 2 ) for the current user would be exceeded. .It Bq Er EMFILE The per-process descriptor table is full. .It Bq Er ENFILE The system file table is full. .El .Pp The .Fn kevent system call fails if: .Bl -tag -width Er .It Bq Er EACCES The process does not have permission to register a filter. .It Bq Er EFAULT There was an error reading or writing the .Va kevent structure. .It Bq Er EBADF The specified descriptor is invalid. .It Bq Er EINTR A signal was delivered before the timeout expired and before any events were placed on the kqueue for return. .It Bq Er EINTR A cancellation request was delivered to the thread, but not yet handled. .It Bq Er EINVAL The specified time limit or filter is invalid. .It Bq Er EINVAL The specified length of the event or change lists is negative. .It Bq Er ENOENT The event could not be found to be modified or deleted. .It Bq Er ENOMEM No memory was available to register the event or, in the special case of a timer, the maximum number of timers has been exceeded. This maximum is configurable via the .Va kern.kq_calloutmax sysctl. .It Bq Er ESRCH The specified process to attach to does not exist. .El .Pp When .Fn kevent call fails with .Er EINTR error, all changes in the .Fa changelist have been applied. .Sh SEE ALSO .Xr aio_error 2 , .Xr aio_read 2 , .Xr aio_return 2 , .Xr poll 2 , .Xr read 2 , .Xr select 2 , .Xr sigaction 2 , .Xr write 2 , .Xr pthread_setcancelstate 3 , .Xr signal 3 .Rs .%A Jonathan Lemon .%T "Kqueue: A Generic and Scalable Event Notification Facility" .%I USENIX Association .%B Proceedings of the FREENIX Track: 2001 USENIX Annual Technical Conference .%D June 25-30, 2001 .\".http://www.usenix.org/event/usenix01/freenix01/full_papers/lemon/lemon.pdf .Re .Sh HISTORY The .Fn kqueue and .Fn kevent system calls first appeared in .Fx 4.1 . .Sh AUTHORS The .Fn kqueue system and this manual page were written by .An Jonathan Lemon Aq Mt jlemon@FreeBSD.org . .Sh BUGS .Pp In versions older than .Fx 12.0 , .In sys/event.h failed to parse without including .In sys/types.h manually. diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 0da4325ccd6a..5cafa0c803fd 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1,2833 +1,2833 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1999,2000,2001 Jonathan Lemon * Copyright 2004 John-Mark Gurney * Copyright (c) 2009 Apple, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_ktrace.h" #include "opt_kqueue.h" #ifdef COMPAT_FREEBSD11 #define _WANT_FREEBSD11_KEVENT #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTRACE #include #endif #include #include static MALLOC_DEFINE(M_KQUEUE, "kqueue", "memory for kqueue system"); /* * This lock is used if multiple kq locks are required. This possibly * should be made into a per proc lock. */ static struct mtx kq_global; MTX_SYSINIT(kq_global, &kq_global, "kqueue order", MTX_DEF); #define KQ_GLOBAL_LOCK(lck, haslck) do { \ if (!haslck) \ mtx_lock(lck); \ haslck = 1; \ } while (0) #define KQ_GLOBAL_UNLOCK(lck, haslck) do { \ if (haslck) \ mtx_unlock(lck); \ haslck = 0; \ } while (0) TASKQUEUE_DEFINE_THREAD(kqueue_ctx); static int kevent_copyout(void *arg, struct kevent *kevp, int count); static int kevent_copyin(void *arg, struct kevent *kevp, int count); static int kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int mflag); static int kqueue_acquire(struct file *fp, struct kqueue **kqp); static void kqueue_release(struct kqueue *kq, int locked); static void kqueue_destroy(struct kqueue *kq); static void kqueue_drain(struct kqueue *kq, struct thread *td); static int kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident, int mflag); static void kqueue_task(void *arg, int pending); static int kqueue_scan(struct kqueue *kq, int maxevents, struct kevent_copyops *k_ops, const struct timespec *timeout, struct kevent *keva, struct thread *td); static void kqueue_wakeup(struct kqueue *kq); static struct filterops *kqueue_fo_find(int filt); static void kqueue_fo_release(int filt); struct g_kevent_args; static int kern_kevent_generic(struct thread *td, struct g_kevent_args *uap, struct kevent_copyops *k_ops, const char *struct_name); static fo_ioctl_t kqueue_ioctl; static fo_poll_t kqueue_poll; static fo_kqfilter_t kqueue_kqfilter; static fo_stat_t kqueue_stat; static fo_close_t kqueue_close; static fo_fill_kinfo_t kqueue_fill_kinfo; static struct fileops kqueueops = { .fo_read = invfo_rdwr, .fo_write = invfo_rdwr, .fo_truncate = invfo_truncate, .fo_ioctl = kqueue_ioctl, .fo_poll = kqueue_poll, .fo_kqfilter = kqueue_kqfilter, .fo_stat = kqueue_stat, .fo_close = kqueue_close, .fo_chmod = invfo_chmod, .fo_chown = invfo_chown, .fo_sendfile = invfo_sendfile, .fo_fill_kinfo = kqueue_fill_kinfo, }; static int knote_attach(struct knote *kn, struct kqueue *kq); static void knote_drop(struct knote *kn, struct thread *td); static void knote_drop_detached(struct knote *kn, struct thread *td); static void knote_enqueue(struct knote *kn); static void knote_dequeue(struct knote *kn); static void knote_init(void); static struct knote *knote_alloc(int mflag); static void knote_free(struct knote *kn); static void filt_kqdetach(struct knote *kn); static int filt_kqueue(struct knote *kn, long hint); static int filt_procattach(struct knote *kn); static void filt_procdetach(struct knote *kn); static int filt_proc(struct knote *kn, long hint); static int filt_fileattach(struct knote *kn); static void filt_timerexpire(void *knx); static void filt_timerexpire_l(struct knote *kn, bool proc_locked); static int filt_timerattach(struct knote *kn); static void filt_timerdetach(struct knote *kn); static void filt_timerstart(struct knote *kn, sbintime_t to); static void filt_timertouch(struct knote *kn, struct kevent *kev, u_long type); static int filt_timervalidate(struct knote *kn, sbintime_t *to); static int filt_timer(struct knote *kn, long hint); static int filt_userattach(struct knote *kn); static void filt_userdetach(struct knote *kn); static int filt_user(struct knote *kn, long hint); static void filt_usertouch(struct knote *kn, struct kevent *kev, u_long type); static struct filterops file_filtops = { .f_isfd = 1, .f_attach = filt_fileattach, }; static struct filterops kqread_filtops = { .f_isfd = 1, .f_detach = filt_kqdetach, .f_event = filt_kqueue, }; /* XXX - move to kern_proc.c? */ static struct filterops proc_filtops = { .f_isfd = 0, .f_attach = filt_procattach, .f_detach = filt_procdetach, .f_event = filt_proc, }; static struct filterops timer_filtops = { .f_isfd = 0, .f_attach = filt_timerattach, .f_detach = filt_timerdetach, .f_event = filt_timer, .f_touch = filt_timertouch, }; static struct filterops user_filtops = { .f_attach = filt_userattach, .f_detach = filt_userdetach, .f_event = filt_user, .f_touch = filt_usertouch, }; static uma_zone_t knote_zone; static unsigned int __exclusive_cache_line kq_ncallouts; static unsigned int kq_calloutmax = 4 * 1024; SYSCTL_UINT(_kern, OID_AUTO, kq_calloutmax, CTLFLAG_RW, &kq_calloutmax, 0, "Maximum number of callouts allocated for kqueue"); /* XXX - ensure not influx ? */ #define KNOTE_ACTIVATE(kn, islock) do { \ if ((islock)) \ mtx_assert(&(kn)->kn_kq->kq_lock, MA_OWNED); \ else \ KQ_LOCK((kn)->kn_kq); \ (kn)->kn_status |= KN_ACTIVE; \ if (((kn)->kn_status & (KN_QUEUED | KN_DISABLED)) == 0) \ knote_enqueue((kn)); \ if (!(islock)) \ KQ_UNLOCK((kn)->kn_kq); \ } while (0) #define KQ_LOCK(kq) do { \ mtx_lock(&(kq)->kq_lock); \ } while (0) #define KQ_FLUX_WAKEUP(kq) do { \ if (((kq)->kq_state & KQ_FLUXWAIT) == KQ_FLUXWAIT) { \ (kq)->kq_state &= ~KQ_FLUXWAIT; \ wakeup((kq)); \ } \ } while (0) #define KQ_UNLOCK_FLUX(kq) do { \ KQ_FLUX_WAKEUP(kq); \ mtx_unlock(&(kq)->kq_lock); \ } while (0) #define KQ_UNLOCK(kq) do { \ mtx_unlock(&(kq)->kq_lock); \ } while (0) #define KQ_OWNED(kq) do { \ mtx_assert(&(kq)->kq_lock, MA_OWNED); \ } while (0) #define KQ_NOTOWNED(kq) do { \ mtx_assert(&(kq)->kq_lock, MA_NOTOWNED); \ } while (0) static struct knlist * kn_list_lock(struct knote *kn) { struct knlist *knl; knl = kn->kn_knlist; if (knl != NULL) knl->kl_lock(knl->kl_lockarg); return (knl); } static void kn_list_unlock(struct knlist *knl) { bool do_free; if (knl == NULL) return; do_free = knl->kl_autodestroy && knlist_empty(knl); knl->kl_unlock(knl->kl_lockarg); if (do_free) { knlist_destroy(knl); free(knl, M_KQUEUE); } } static bool kn_in_flux(struct knote *kn) { return (kn->kn_influx > 0); } static void kn_enter_flux(struct knote *kn) { KQ_OWNED(kn->kn_kq); MPASS(kn->kn_influx < INT_MAX); kn->kn_influx++; } static bool kn_leave_flux(struct knote *kn) { KQ_OWNED(kn->kn_kq); MPASS(kn->kn_influx > 0); kn->kn_influx--; return (kn->kn_influx == 0); } #define KNL_ASSERT_LOCK(knl, islocked) do { \ if (islocked) \ KNL_ASSERT_LOCKED(knl); \ else \ KNL_ASSERT_UNLOCKED(knl); \ } while (0) #ifdef INVARIANTS #define KNL_ASSERT_LOCKED(knl) do { \ knl->kl_assert_lock((knl)->kl_lockarg, LA_LOCKED); \ } while (0) #define KNL_ASSERT_UNLOCKED(knl) do { \ knl->kl_assert_lock((knl)->kl_lockarg, LA_UNLOCKED); \ } while (0) #else /* !INVARIANTS */ #define KNL_ASSERT_LOCKED(knl) do {} while (0) #define KNL_ASSERT_UNLOCKED(knl) do {} while (0) #endif /* INVARIANTS */ #ifndef KN_HASHSIZE #define KN_HASHSIZE 64 /* XXX should be tunable */ #endif #define KN_HASH(val, mask) (((val) ^ (val >> 8)) & (mask)) static int filt_nullattach(struct knote *kn) { return (ENXIO); }; struct filterops null_filtops = { .f_isfd = 0, .f_attach = filt_nullattach, }; /* XXX - make SYSINIT to add these, and move into respective modules. */ extern struct filterops sig_filtops; extern struct filterops fs_filtops; /* * Table for all system-defined filters. */ static struct mtx filterops_lock; MTX_SYSINIT(kqueue_filterops, &filterops_lock, "protect sysfilt_ops", MTX_DEF); static struct { struct filterops *for_fop; int for_nolock; int for_refcnt; } sysfilt_ops[EVFILT_SYSCOUNT] = { { &file_filtops, 1 }, /* EVFILT_READ */ { &file_filtops, 1 }, /* EVFILT_WRITE */ { &null_filtops }, /* EVFILT_AIO */ { &file_filtops, 1 }, /* EVFILT_VNODE */ { &proc_filtops, 1 }, /* EVFILT_PROC */ { &sig_filtops, 1 }, /* EVFILT_SIGNAL */ { &timer_filtops, 1 }, /* EVFILT_TIMER */ { &file_filtops, 1 }, /* EVFILT_PROCDESC */ { &fs_filtops, 1 }, /* EVFILT_FS */ { &null_filtops }, /* EVFILT_LIO */ { &user_filtops, 1 }, /* EVFILT_USER */ { &null_filtops }, /* EVFILT_SENDFILE */ { &file_filtops, 1 }, /* EVFILT_EMPTY */ }; /* * Simple redirection for all cdevsw style objects to call their fo_kqfilter * method. */ static int filt_fileattach(struct knote *kn) { return (fo_kqfilter(kn->kn_fp, kn)); } /*ARGSUSED*/ static int kqueue_kqfilter(struct file *fp, struct knote *kn) { struct kqueue *kq = kn->kn_fp->f_data; if (kn->kn_filter != EVFILT_READ) return (EINVAL); kn->kn_status |= KN_KQUEUE; kn->kn_fop = &kqread_filtops; knlist_add(&kq->kq_sel.si_note, kn, 0); return (0); } static void filt_kqdetach(struct knote *kn) { struct kqueue *kq = kn->kn_fp->f_data; knlist_remove(&kq->kq_sel.si_note, kn, 0); } /*ARGSUSED*/ static int filt_kqueue(struct knote *kn, long hint) { struct kqueue *kq = kn->kn_fp->f_data; kn->kn_data = kq->kq_count; return (kn->kn_data > 0); } /* XXX - move to kern_proc.c? */ static int filt_procattach(struct knote *kn) { struct proc *p; int error; bool exiting, immediate; exiting = immediate = false; if (kn->kn_sfflags & NOTE_EXIT) p = pfind_any(kn->kn_id); else p = pfind(kn->kn_id); if (p == NULL) return (ESRCH); if (p->p_flag & P_WEXIT) exiting = true; if ((error = p_cansee(curthread, p))) { PROC_UNLOCK(p); return (error); } kn->kn_ptr.p_proc = p; kn->kn_flags |= EV_CLEAR; /* automatically set */ /* * Internal flag indicating registration done by kernel for the * purposes of getting a NOTE_CHILD notification. */ if (kn->kn_flags & EV_FLAG2) { kn->kn_flags &= ~EV_FLAG2; kn->kn_data = kn->kn_sdata; /* ppid */ kn->kn_fflags = NOTE_CHILD; kn->kn_sfflags &= ~(NOTE_EXIT | NOTE_EXEC | NOTE_FORK); immediate = true; /* Force immediate activation of child note. */ } /* * Internal flag indicating registration done by kernel (for other than * NOTE_CHILD). */ if (kn->kn_flags & EV_FLAG1) { kn->kn_flags &= ~EV_FLAG1; } knlist_add(p->p_klist, kn, 1); /* * Immediately activate any child notes or, in the case of a zombie * target process, exit notes. The latter is necessary to handle the * case where the target process, e.g. a child, dies before the kevent * is registered. */ if (immediate || (exiting && filt_proc(kn, NOTE_EXIT))) KNOTE_ACTIVATE(kn, 0); PROC_UNLOCK(p); return (0); } /* * The knote may be attached to a different process, which may exit, * leaving nothing for the knote to be attached to. So when the process * exits, the knote is marked as DETACHED and also flagged as ONESHOT so * it will be deleted when read out. However, as part of the knote deletion, * this routine is called, so a check is needed to avoid actually performing * a detach, because the original process does not exist any more. */ /* XXX - move to kern_proc.c? */ static void filt_procdetach(struct knote *kn) { knlist_remove(kn->kn_knlist, kn, 0); kn->kn_ptr.p_proc = NULL; } /* XXX - move to kern_proc.c? */ static int filt_proc(struct knote *kn, long hint) { struct proc *p; u_int event; p = kn->kn_ptr.p_proc; if (p == NULL) /* already activated, from attach filter */ return (0); /* Mask off extra data. */ event = (u_int)hint & NOTE_PCTRLMASK; /* If the user is interested in this event, record it. */ if (kn->kn_sfflags & event) kn->kn_fflags |= event; /* Process is gone, so flag the event as finished. */ if (event == NOTE_EXIT) { kn->kn_flags |= EV_EOF | EV_ONESHOT; kn->kn_ptr.p_proc = NULL; if (kn->kn_fflags & NOTE_EXIT) kn->kn_data = KW_EXITCODE(p->p_xexit, p->p_xsig); if (kn->kn_fflags == 0) kn->kn_flags |= EV_DROP; return (1); } return (kn->kn_fflags != 0); } /* * Called when the process forked. It mostly does the same as the * knote(), activating all knotes registered to be activated when the * process forked. Additionally, for each knote attached to the * parent, check whether user wants to track the new process. If so * attach a new knote to it, and immediately report an event with the * child's pid. */ void knote_fork(struct knlist *list, int pid) { struct kqueue *kq; struct knote *kn; struct kevent kev; int error; MPASS(list != NULL); KNL_ASSERT_LOCKED(list); if (SLIST_EMPTY(&list->kl_list)) return; memset(&kev, 0, sizeof(kev)); SLIST_FOREACH(kn, &list->kl_list, kn_selnext) { kq = kn->kn_kq; KQ_LOCK(kq); if (kn_in_flux(kn) && (kn->kn_status & KN_SCAN) == 0) { KQ_UNLOCK(kq); continue; } /* * The same as knote(), activate the event. */ if ((kn->kn_sfflags & NOTE_TRACK) == 0) { if (kn->kn_fop->f_event(kn, NOTE_FORK)) KNOTE_ACTIVATE(kn, 1); KQ_UNLOCK(kq); continue; } /* * The NOTE_TRACK case. In addition to the activation * of the event, we need to register new events to * track the child. Drop the locks in preparation for * the call to kqueue_register(). */ kn_enter_flux(kn); KQ_UNLOCK(kq); list->kl_unlock(list->kl_lockarg); /* * Activate existing knote and register tracking knotes with * new process. * * First register a knote to get just the child notice. This * must be a separate note from a potential NOTE_EXIT * notification since both NOTE_CHILD and NOTE_EXIT are defined * to use the data field (in conflicting ways). */ kev.ident = pid; kev.filter = kn->kn_filter; kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_ONESHOT | EV_FLAG2; kev.fflags = kn->kn_sfflags; kev.data = kn->kn_id; /* parent */ kev.udata = kn->kn_kevent.udata;/* preserve udata */ error = kqueue_register(kq, &kev, NULL, M_NOWAIT); if (error) kn->kn_fflags |= NOTE_TRACKERR; /* * Then register another knote to track other potential events * from the new process. */ kev.ident = pid; kev.filter = kn->kn_filter; kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1; kev.fflags = kn->kn_sfflags; kev.data = kn->kn_id; /* parent */ kev.udata = kn->kn_kevent.udata;/* preserve udata */ error = kqueue_register(kq, &kev, NULL, M_NOWAIT); if (error) kn->kn_fflags |= NOTE_TRACKERR; if (kn->kn_fop->f_event(kn, NOTE_FORK)) KNOTE_ACTIVATE(kn, 0); list->kl_lock(list->kl_lockarg); KQ_LOCK(kq); kn_leave_flux(kn); KQ_UNLOCK_FLUX(kq); } } /* * XXX: EVFILT_TIMER should perhaps live in kern_time.c beside the * interval timer support code. */ #define NOTE_TIMER_PRECMASK \ (NOTE_SECONDS | NOTE_MSECONDS | NOTE_USECONDS | NOTE_NSECONDS) static sbintime_t timer2sbintime(int64_t data, int flags) { int64_t secs; /* * Macros for converting to the fractional second portion of an * sbintime_t using 64bit multiplication to improve precision. */ #define NS_TO_SBT(ns) (((ns) * (((uint64_t)1 << 63) / 500000000)) >> 32) #define US_TO_SBT(us) (((us) * (((uint64_t)1 << 63) / 500000)) >> 32) #define MS_TO_SBT(ms) (((ms) * (((uint64_t)1 << 63) / 500)) >> 32) switch (flags & NOTE_TIMER_PRECMASK) { case NOTE_SECONDS: #ifdef __LP64__ if (data > (SBT_MAX / SBT_1S)) return (SBT_MAX); #endif return ((sbintime_t)data << 32); case NOTE_MSECONDS: /* FALLTHROUGH */ case 0: if (data >= 1000) { secs = data / 1000; #ifdef __LP64__ if (secs > (SBT_MAX / SBT_1S)) return (SBT_MAX); #endif return (secs << 32 | MS_TO_SBT(data % 1000)); } return (MS_TO_SBT(data)); case NOTE_USECONDS: if (data >= 1000000) { secs = data / 1000000; #ifdef __LP64__ if (secs > (SBT_MAX / SBT_1S)) return (SBT_MAX); #endif return (secs << 32 | US_TO_SBT(data % 1000000)); } return (US_TO_SBT(data)); case NOTE_NSECONDS: if (data >= 1000000000) { secs = data / 1000000000; #ifdef __LP64__ if (secs > (SBT_MAX / SBT_1S)) return (SBT_MAX); #endif return (secs << 32 | NS_TO_SBT(data % 1000000000)); } return (NS_TO_SBT(data)); default: break; } return (-1); } struct kq_timer_cb_data { struct callout c; struct proc *p; struct knote *kn; int cpuid; int flags; TAILQ_ENTRY(kq_timer_cb_data) link; sbintime_t next; /* next timer event fires at */ sbintime_t to; /* precalculated timer period, 0 for abs */ }; #define KQ_TIMER_CB_ENQUEUED 0x01 static void kqtimer_sched_callout(struct kq_timer_cb_data *kc) { callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kc->kn, kc->cpuid, C_ABSOLUTE); } void kqtimer_proc_continue(struct proc *p) { struct kq_timer_cb_data *kc, *kc1; struct bintime bt; sbintime_t now; PROC_LOCK_ASSERT(p, MA_OWNED); getboottimebin(&bt); now = bttosbt(bt); TAILQ_FOREACH_SAFE(kc, &p->p_kqtim_stop, link, kc1) { TAILQ_REMOVE(&p->p_kqtim_stop, kc, link); kc->flags &= ~KQ_TIMER_CB_ENQUEUED; if (kc->next <= now) filt_timerexpire_l(kc->kn, true); else kqtimer_sched_callout(kc); } } static void filt_timerexpire_l(struct knote *kn, bool proc_locked) { struct kq_timer_cb_data *kc; struct proc *p; uint64_t delta; sbintime_t now; kc = kn->kn_ptr.p_v; if ((kn->kn_flags & EV_ONESHOT) != 0 || kc->to == 0) { kn->kn_data++; KNOTE_ACTIVATE(kn, 0); return; } now = sbinuptime(); if (now >= kc->next) { delta = (now - kc->next) / kc->to; if (delta == 0) delta = 1; kn->kn_data += delta; kc->next += delta * kc->to; if (now >= kc->next) /* overflow */ kc->next = now + kc->to; KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */ } /* * Initial check for stopped kc->p is racy. It is fine to * miss the set of the stop flags, at worst we would schedule * one more callout. On the other hand, it is not fine to not * schedule when we we missed clearing of the flags, we * recheck them under the lock and observe consistent state. */ p = kc->p; if (P_SHOULDSTOP(p) || P_KILLED(p)) { if (!proc_locked) PROC_LOCK(p); if (P_SHOULDSTOP(p) || P_KILLED(p)) { if ((kc->flags & KQ_TIMER_CB_ENQUEUED) == 0) { kc->flags |= KQ_TIMER_CB_ENQUEUED; TAILQ_INSERT_TAIL(&p->p_kqtim_stop, kc, link); } if (!proc_locked) PROC_UNLOCK(p); return; } if (!proc_locked) PROC_UNLOCK(p); } kqtimer_sched_callout(kc); } static void filt_timerexpire(void *knx) { filt_timerexpire_l(knx, false); } /* * data contains amount of time to sleep */ static int filt_timervalidate(struct knote *kn, sbintime_t *to) { struct bintime bt; sbintime_t sbt; if (kn->kn_sdata < 0) return (EINVAL); if (kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0) kn->kn_sdata = 1; /* * The only fflags values supported are the timer unit * (precision) and the absolute time indicator. */ if ((kn->kn_sfflags & ~(NOTE_TIMER_PRECMASK | NOTE_ABSTIME)) != 0) return (EINVAL); *to = timer2sbintime(kn->kn_sdata, kn->kn_sfflags); if (*to < 0) return (EINVAL); if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) { getboottimebin(&bt); sbt = bttosbt(bt); *to = MAX(0, *to - sbt); } return (0); } static int filt_timerattach(struct knote *kn) { struct kq_timer_cb_data *kc; sbintime_t to; int error; to = -1; error = filt_timervalidate(kn, &to); if (error != 0) return (error); KASSERT(to > 0 || (kn->kn_flags & EV_ONESHOT) != 0 || (kn->kn_sfflags & NOTE_ABSTIME) != 0, ("%s: periodic timer has a calculated zero timeout", __func__)); KASSERT(to >= 0, ("%s: timer has a calculated negative timeout", __func__)); if (atomic_fetchadd_int(&kq_ncallouts, 1) + 1 > kq_calloutmax) { atomic_subtract_int(&kq_ncallouts, 1); return (ENOMEM); } if ((kn->kn_sfflags & NOTE_ABSTIME) == 0) kn->kn_flags |= EV_CLEAR; /* automatically set */ kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */ kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK); kc->kn = kn; kc->p = curproc; kc->cpuid = PCPU_GET(cpuid); kc->flags = 0; callout_init(&kc->c, 1); filt_timerstart(kn, to); return (0); } static void filt_timerstart(struct knote *kn, sbintime_t to) { struct kq_timer_cb_data *kc; kc = kn->kn_ptr.p_v; if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) { kc->next = to; kc->to = 0; } else { kc->next = to + sbinuptime(); kc->to = to; } kqtimer_sched_callout(kc); } static void filt_timerdetach(struct knote *kn) { struct kq_timer_cb_data *kc; unsigned int old __unused; bool pending; kc = kn->kn_ptr.p_v; do { callout_drain(&kc->c); /* * kqtimer_proc_continue() might have rescheduled this callout. * Double-check, using the process mutex as an interlock. */ PROC_LOCK(kc->p); if ((kc->flags & KQ_TIMER_CB_ENQUEUED) != 0) { kc->flags &= ~KQ_TIMER_CB_ENQUEUED; TAILQ_REMOVE(&kc->p->p_kqtim_stop, kc, link); } pending = callout_pending(&kc->c); PROC_UNLOCK(kc->p); } while (pending); free(kc, M_KQUEUE); old = atomic_fetchadd_int(&kq_ncallouts, -1); KASSERT(old > 0, ("Number of callouts cannot become negative")); kn->kn_status |= KN_DETACHED; /* knlist_remove sets it */ } static void filt_timertouch(struct knote *kn, struct kevent *kev, u_long type) { struct kq_timer_cb_data *kc; struct kqueue *kq; sbintime_t to; int error; switch (type) { case EVENT_REGISTER: /* Handle re-added timers that update data/fflags */ if (kev->flags & EV_ADD) { kc = kn->kn_ptr.p_v; /* Drain any existing callout. */ callout_drain(&kc->c); /* Throw away any existing undelivered record * of the timer expiration. This is done under * the presumption that if a process is * re-adding this timer with new parameters, * it is no longer interested in what may have * happened under the old parameters. If it is * interested, it can wait for the expiration, * delete the old timer definition, and then * add the new one. * * This has to be done while the kq is locked: * - if enqueued, dequeue * - make it no longer active * - clear the count of expiration events */ kq = kn->kn_kq; KQ_LOCK(kq); if (kn->kn_status & KN_QUEUED) knote_dequeue(kn); kn->kn_status &= ~KN_ACTIVE; kn->kn_data = 0; KQ_UNLOCK(kq); /* Reschedule timer based on new data/fflags */ kn->kn_sfflags = kev->fflags; kn->kn_sdata = kev->data; error = filt_timervalidate(kn, &to); if (error != 0) { kn->kn_flags |= EV_ERROR; kn->kn_data = error; } else filt_timerstart(kn, to); } break; case EVENT_PROCESS: *kev = kn->kn_kevent; if (kn->kn_flags & EV_CLEAR) { kn->kn_data = 0; kn->kn_fflags = 0; } break; default: panic("filt_timertouch() - invalid type (%ld)", type); break; } } static int filt_timer(struct knote *kn, long hint) { return (kn->kn_data != 0); } static int filt_userattach(struct knote *kn) { /* * EVFILT_USER knotes are not attached to anything in the kernel. */ kn->kn_hook = NULL; if (kn->kn_fflags & NOTE_TRIGGER) kn->kn_hookid = 1; else kn->kn_hookid = 0; return (0); } static void filt_userdetach(__unused struct knote *kn) { /* * EVFILT_USER knotes are not attached to anything in the kernel. */ } static int filt_user(struct knote *kn, __unused long hint) { return (kn->kn_hookid); } static void filt_usertouch(struct knote *kn, struct kevent *kev, u_long type) { u_int ffctrl; switch (type) { case EVENT_REGISTER: if (kev->fflags & NOTE_TRIGGER) kn->kn_hookid = 1; ffctrl = kev->fflags & NOTE_FFCTRLMASK; kev->fflags &= NOTE_FFLAGSMASK; switch (ffctrl) { case NOTE_FFNOP: break; case NOTE_FFAND: kn->kn_sfflags &= kev->fflags; break; case NOTE_FFOR: kn->kn_sfflags |= kev->fflags; break; case NOTE_FFCOPY: kn->kn_sfflags = kev->fflags; break; default: /* XXX Return error? */ break; } kn->kn_sdata = kev->data; if (kev->flags & EV_CLEAR) { kn->kn_hookid = 0; kn->kn_data = 0; kn->kn_fflags = 0; } break; case EVENT_PROCESS: *kev = kn->kn_kevent; kev->fflags = kn->kn_sfflags; kev->data = kn->kn_sdata; if (kn->kn_flags & EV_CLEAR) { kn->kn_hookid = 0; kn->kn_data = 0; kn->kn_fflags = 0; } break; default: panic("filt_usertouch() - invalid type (%ld)", type); break; } } int sys_kqueue(struct thread *td, struct kqueue_args *uap) { return (kern_kqueue(td, 0, NULL)); } int -sys_kqueue1(struct thread *td, struct kqueue1_args *uap) +sys_kqueuex(struct thread *td, struct kqueuex_args *uap) { int flags; if ((uap->flags & ~(KQUEUE_CLOEXEC)) != 0) return (EINVAL); flags = 0; if ((uap->flags & KQUEUE_CLOEXEC) != 0) flags |= O_CLOEXEC; return (kern_kqueue(td, flags, NULL)); } static void kqueue_init(struct kqueue *kq) { mtx_init(&kq->kq_lock, "kqueue", NULL, MTX_DEF | MTX_DUPOK); TAILQ_INIT(&kq->kq_head); knlist_init_mtx(&kq->kq_sel.si_note, &kq->kq_lock); TASK_INIT(&kq->kq_task, 0, kqueue_task, kq); } int kern_kqueue(struct thread *td, int flags, struct filecaps *fcaps) { struct filedesc *fdp; struct kqueue *kq; struct file *fp; struct ucred *cred; int fd, error; fdp = td->td_proc->p_fd; cred = td->td_ucred; if (!chgkqcnt(cred->cr_ruidinfo, 1, lim_cur(td, RLIMIT_KQUEUES))) return (ENOMEM); error = falloc_caps(td, &fp, &fd, flags, fcaps); if (error != 0) { chgkqcnt(cred->cr_ruidinfo, -1, 0); return (error); } /* An extra reference on `fp' has been held for us by falloc(). */ kq = malloc(sizeof *kq, M_KQUEUE, M_WAITOK | M_ZERO); kqueue_init(kq); kq->kq_fdp = fdp; kq->kq_cred = crhold(cred); FILEDESC_XLOCK(fdp); TAILQ_INSERT_HEAD(&fdp->fd_kqlist, kq, kq_list); FILEDESC_XUNLOCK(fdp); finit(fp, FREAD | FWRITE, DTYPE_KQUEUE, kq, &kqueueops); fdrop(fp, td); td->td_retval[0] = fd; return (0); } struct g_kevent_args { int fd; const void *changelist; int nchanges; void *eventlist; int nevents; const struct timespec *timeout; }; int sys_kevent(struct thread *td, struct kevent_args *uap) { struct kevent_copyops k_ops = { .arg = uap, .k_copyout = kevent_copyout, .k_copyin = kevent_copyin, .kevent_size = sizeof(struct kevent), }; struct g_kevent_args gk_args = { .fd = uap->fd, .changelist = uap->changelist, .nchanges = uap->nchanges, .eventlist = uap->eventlist, .nevents = uap->nevents, .timeout = uap->timeout, }; return (kern_kevent_generic(td, &gk_args, &k_ops, "kevent")); } static int kern_kevent_generic(struct thread *td, struct g_kevent_args *uap, struct kevent_copyops *k_ops, const char *struct_name) { struct timespec ts, *tsp; #ifdef KTRACE struct kevent *eventlist = uap->eventlist; #endif int error; if (uap->timeout != NULL) { error = copyin(uap->timeout, &ts, sizeof(ts)); if (error) return (error); tsp = &ts; } else tsp = NULL; #ifdef KTRACE if (KTRPOINT(td, KTR_STRUCT_ARRAY)) ktrstructarray(struct_name, UIO_USERSPACE, uap->changelist, uap->nchanges, k_ops->kevent_size); #endif error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents, k_ops, tsp); #ifdef KTRACE if (error == 0 && KTRPOINT(td, KTR_STRUCT_ARRAY)) ktrstructarray(struct_name, UIO_USERSPACE, eventlist, td->td_retval[0], k_ops->kevent_size); #endif return (error); } /* * Copy 'count' items into the destination list pointed to by uap->eventlist. */ static int kevent_copyout(void *arg, struct kevent *kevp, int count) { struct kevent_args *uap; int error; KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); uap = (struct kevent_args *)arg; error = copyout(kevp, uap->eventlist, count * sizeof *kevp); if (error == 0) uap->eventlist += count; return (error); } /* * Copy 'count' items from the list pointed to by uap->changelist. */ static int kevent_copyin(void *arg, struct kevent *kevp, int count) { struct kevent_args *uap; int error; KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); uap = (struct kevent_args *)arg; error = copyin(uap->changelist, kevp, count * sizeof *kevp); if (error == 0) uap->changelist += count; return (error); } #ifdef COMPAT_FREEBSD11 static int kevent11_copyout(void *arg, struct kevent *kevp, int count) { struct freebsd11_kevent_args *uap; struct freebsd11_kevent kev11; int error, i; KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); uap = (struct freebsd11_kevent_args *)arg; for (i = 0; i < count; i++) { kev11.ident = kevp->ident; kev11.filter = kevp->filter; kev11.flags = kevp->flags; kev11.fflags = kevp->fflags; kev11.data = kevp->data; kev11.udata = kevp->udata; error = copyout(&kev11, uap->eventlist, sizeof(kev11)); if (error != 0) break; uap->eventlist++; kevp++; } return (error); } /* * Copy 'count' items from the list pointed to by uap->changelist. */ static int kevent11_copyin(void *arg, struct kevent *kevp, int count) { struct freebsd11_kevent_args *uap; struct freebsd11_kevent kev11; int error, i; KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); uap = (struct freebsd11_kevent_args *)arg; for (i = 0; i < count; i++) { error = copyin(uap->changelist, &kev11, sizeof(kev11)); if (error != 0) break; kevp->ident = kev11.ident; kevp->filter = kev11.filter; kevp->flags = kev11.flags; kevp->fflags = kev11.fflags; kevp->data = (uintptr_t)kev11.data; kevp->udata = kev11.udata; bzero(&kevp->ext, sizeof(kevp->ext)); uap->changelist++; kevp++; } return (error); } int freebsd11_kevent(struct thread *td, struct freebsd11_kevent_args *uap) { struct kevent_copyops k_ops = { .arg = uap, .k_copyout = kevent11_copyout, .k_copyin = kevent11_copyin, .kevent_size = sizeof(struct freebsd11_kevent), }; struct g_kevent_args gk_args = { .fd = uap->fd, .changelist = uap->changelist, .nchanges = uap->nchanges, .eventlist = uap->eventlist, .nevents = uap->nevents, .timeout = uap->timeout, }; return (kern_kevent_generic(td, &gk_args, &k_ops, "freebsd11_kevent")); } #endif int kern_kevent(struct thread *td, int fd, int nchanges, int nevents, struct kevent_copyops *k_ops, const struct timespec *timeout) { cap_rights_t rights; struct file *fp; int error; cap_rights_init_zero(&rights); if (nchanges > 0) cap_rights_set_one(&rights, CAP_KQUEUE_CHANGE); if (nevents > 0) cap_rights_set_one(&rights, CAP_KQUEUE_EVENT); error = fget(td, fd, &rights, &fp); if (error != 0) return (error); error = kern_kevent_fp(td, fp, nchanges, nevents, k_ops, timeout); fdrop(fp, td); return (error); } static int kqueue_kevent(struct kqueue *kq, struct thread *td, int nchanges, int nevents, struct kevent_copyops *k_ops, const struct timespec *timeout) { struct kevent keva[KQ_NEVENTS]; struct kevent *kevp, *changes; int i, n, nerrors, error; if (nchanges < 0) return (EINVAL); nerrors = 0; while (nchanges > 0) { n = nchanges > KQ_NEVENTS ? KQ_NEVENTS : nchanges; error = k_ops->k_copyin(k_ops->arg, keva, n); if (error) return (error); changes = keva; for (i = 0; i < n; i++) { kevp = &changes[i]; if (!kevp->filter) continue; kevp->flags &= ~EV_SYSFLAGS; error = kqueue_register(kq, kevp, td, M_WAITOK); if (error || (kevp->flags & EV_RECEIPT)) { if (nevents == 0) return (error); kevp->flags = EV_ERROR; kevp->data = error; (void)k_ops->k_copyout(k_ops->arg, kevp, 1); nevents--; nerrors++; } } nchanges -= n; } if (nerrors) { td->td_retval[0] = nerrors; return (0); } return (kqueue_scan(kq, nevents, k_ops, timeout, keva, td)); } int kern_kevent_fp(struct thread *td, struct file *fp, int nchanges, int nevents, struct kevent_copyops *k_ops, const struct timespec *timeout) { struct kqueue *kq; int error; error = kqueue_acquire(fp, &kq); if (error != 0) return (error); error = kqueue_kevent(kq, td, nchanges, nevents, k_ops, timeout); kqueue_release(kq, 0); return (error); } /* * Performs a kevent() call on a temporarily created kqueue. This can be * used to perform one-shot polling, similar to poll() and select(). */ int kern_kevent_anonymous(struct thread *td, int nevents, struct kevent_copyops *k_ops) { struct kqueue kq = {}; int error; kqueue_init(&kq); kq.kq_refcnt = 1; error = kqueue_kevent(&kq, td, nevents, nevents, k_ops, NULL); kqueue_drain(&kq, td); kqueue_destroy(&kq); return (error); } int kqueue_add_filteropts(int filt, struct filterops *filtops) { int error; error = 0; if (filt > 0 || filt + EVFILT_SYSCOUNT < 0) { printf( "trying to add a filterop that is out of range: %d is beyond %d\n", ~filt, EVFILT_SYSCOUNT); return EINVAL; } mtx_lock(&filterops_lock); if (sysfilt_ops[~filt].for_fop != &null_filtops && sysfilt_ops[~filt].for_fop != NULL) error = EEXIST; else { sysfilt_ops[~filt].for_fop = filtops; sysfilt_ops[~filt].for_refcnt = 0; } mtx_unlock(&filterops_lock); return (error); } int kqueue_del_filteropts(int filt) { int error; error = 0; if (filt > 0 || filt + EVFILT_SYSCOUNT < 0) return EINVAL; mtx_lock(&filterops_lock); if (sysfilt_ops[~filt].for_fop == &null_filtops || sysfilt_ops[~filt].for_fop == NULL) error = EINVAL; else if (sysfilt_ops[~filt].for_refcnt != 0) error = EBUSY; else { sysfilt_ops[~filt].for_fop = &null_filtops; sysfilt_ops[~filt].for_refcnt = 0; } mtx_unlock(&filterops_lock); return error; } static struct filterops * kqueue_fo_find(int filt) { if (filt > 0 || filt + EVFILT_SYSCOUNT < 0) return NULL; if (sysfilt_ops[~filt].for_nolock) return sysfilt_ops[~filt].for_fop; mtx_lock(&filterops_lock); sysfilt_ops[~filt].for_refcnt++; if (sysfilt_ops[~filt].for_fop == NULL) sysfilt_ops[~filt].for_fop = &null_filtops; mtx_unlock(&filterops_lock); return sysfilt_ops[~filt].for_fop; } static void kqueue_fo_release(int filt) { if (filt > 0 || filt + EVFILT_SYSCOUNT < 0) return; if (sysfilt_ops[~filt].for_nolock) return; mtx_lock(&filterops_lock); KASSERT(sysfilt_ops[~filt].for_refcnt > 0, ("filter object refcount not valid on release")); sysfilt_ops[~filt].for_refcnt--; mtx_unlock(&filterops_lock); } /* * A ref to kq (obtained via kqueue_acquire) must be held. */ static int kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int mflag) { struct filterops *fops; struct file *fp; struct knote *kn, *tkn; struct knlist *knl; int error, filt, event; int haskqglobal, filedesc_unlock; if ((kev->flags & (EV_ENABLE | EV_DISABLE)) == (EV_ENABLE | EV_DISABLE)) return (EINVAL); fp = NULL; kn = NULL; knl = NULL; error = 0; haskqglobal = 0; filedesc_unlock = 0; filt = kev->filter; fops = kqueue_fo_find(filt); if (fops == NULL) return EINVAL; if (kev->flags & EV_ADD) { /* Reject an invalid flag pair early */ if (kev->flags & EV_KEEPUDATA) { tkn = NULL; error = EINVAL; goto done; } /* * Prevent waiting with locks. Non-sleepable * allocation failures are handled in the loop, only * if the spare knote appears to be actually required. */ tkn = knote_alloc(mflag); } else { tkn = NULL; } findkn: if (fops->f_isfd) { KASSERT(td != NULL, ("td is NULL")); if (kev->ident > INT_MAX) error = EBADF; else error = fget(td, kev->ident, &cap_event_rights, &fp); if (error) goto done; if ((kev->flags & EV_ADD) == EV_ADD && kqueue_expand(kq, fops, kev->ident, M_NOWAIT) != 0) { /* try again */ fdrop(fp, td); fp = NULL; error = kqueue_expand(kq, fops, kev->ident, mflag); if (error) goto done; goto findkn; } if (fp->f_type == DTYPE_KQUEUE) { /* * If we add some intelligence about what we are doing, * we should be able to support events on ourselves. * We need to know when we are doing this to prevent * getting both the knlist lock and the kq lock since * they are the same thing. */ if (fp->f_data == kq) { error = EINVAL; goto done; } /* * Pre-lock the filedesc before the global * lock mutex, see the comment in * kqueue_close(). */ FILEDESC_XLOCK(td->td_proc->p_fd); filedesc_unlock = 1; KQ_GLOBAL_LOCK(&kq_global, haskqglobal); } KQ_LOCK(kq); if (kev->ident < kq->kq_knlistsize) { SLIST_FOREACH(kn, &kq->kq_knlist[kev->ident], kn_link) if (kev->filter == kn->kn_filter) break; } } else { if ((kev->flags & EV_ADD) == EV_ADD) { error = kqueue_expand(kq, fops, kev->ident, mflag); if (error != 0) goto done; } KQ_LOCK(kq); /* * If possible, find an existing knote to use for this kevent. */ if (kev->filter == EVFILT_PROC && (kev->flags & (EV_FLAG1 | EV_FLAG2)) != 0) { /* This is an internal creation of a process tracking * note. Don't attempt to coalesce this with an * existing note. */ ; } else if (kq->kq_knhashmask != 0) { struct klist *list; list = &kq->kq_knhash[ KN_HASH((u_long)kev->ident, kq->kq_knhashmask)]; SLIST_FOREACH(kn, list, kn_link) if (kev->ident == kn->kn_id && kev->filter == kn->kn_filter) break; } } /* knote is in the process of changing, wait for it to stabilize. */ if (kn != NULL && kn_in_flux(kn)) { KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal); if (filedesc_unlock) { FILEDESC_XUNLOCK(td->td_proc->p_fd); filedesc_unlock = 0; } kq->kq_state |= KQ_FLUXWAIT; msleep(kq, &kq->kq_lock, PSOCK | PDROP, "kqflxwt", 0); if (fp != NULL) { fdrop(fp, td); fp = NULL; } goto findkn; } /* * kn now contains the matching knote, or NULL if no match */ if (kn == NULL) { if (kev->flags & EV_ADD) { kn = tkn; tkn = NULL; if (kn == NULL) { KQ_UNLOCK(kq); error = ENOMEM; goto done; } kn->kn_fp = fp; kn->kn_kq = kq; kn->kn_fop = fops; /* * apply reference counts to knote structure, and * do not release it at the end of this routine. */ fops = NULL; fp = NULL; kn->kn_sfflags = kev->fflags; kn->kn_sdata = kev->data; kev->fflags = 0; kev->data = 0; kn->kn_kevent = *kev; kn->kn_kevent.flags &= ~(EV_ADD | EV_DELETE | EV_ENABLE | EV_DISABLE | EV_FORCEONESHOT); kn->kn_status = KN_DETACHED; if ((kev->flags & EV_DISABLE) != 0) kn->kn_status |= KN_DISABLED; kn_enter_flux(kn); error = knote_attach(kn, kq); KQ_UNLOCK(kq); if (error != 0) { tkn = kn; goto done; } if ((error = kn->kn_fop->f_attach(kn)) != 0) { knote_drop_detached(kn, td); goto done; } knl = kn_list_lock(kn); goto done_ev_add; } else { /* No matching knote and the EV_ADD flag is not set. */ KQ_UNLOCK(kq); error = ENOENT; goto done; } } if (kev->flags & EV_DELETE) { kn_enter_flux(kn); KQ_UNLOCK(kq); knote_drop(kn, td); goto done; } if (kev->flags & EV_FORCEONESHOT) { kn->kn_flags |= EV_ONESHOT; KNOTE_ACTIVATE(kn, 1); } if ((kev->flags & EV_ENABLE) != 0) kn->kn_status &= ~KN_DISABLED; else if ((kev->flags & EV_DISABLE) != 0) kn->kn_status |= KN_DISABLED; /* * The user may change some filter values after the initial EV_ADD, * but doing so will not reset any filter which has already been * triggered. */ kn->kn_status |= KN_SCAN; kn_enter_flux(kn); KQ_UNLOCK(kq); knl = kn_list_lock(kn); if ((kev->flags & EV_KEEPUDATA) == 0) kn->kn_kevent.udata = kev->udata; if (!fops->f_isfd && fops->f_touch != NULL) { fops->f_touch(kn, kev, EVENT_REGISTER); } else { kn->kn_sfflags = kev->fflags; kn->kn_sdata = kev->data; } done_ev_add: /* * We can get here with kn->kn_knlist == NULL. This can happen when * the initial attach event decides that the event is "completed" * already, e.g., filt_procattach() is called on a zombie process. It * will call filt_proc() which will remove it from the list, and NULL * kn_knlist. * * KN_DISABLED will be stable while the knote is in flux, so the * unlocked read will not race with an update. */ if ((kn->kn_status & KN_DISABLED) == 0) event = kn->kn_fop->f_event(kn, 0); else event = 0; KQ_LOCK(kq); if (event) kn->kn_status |= KN_ACTIVE; if ((kn->kn_status & (KN_ACTIVE | KN_DISABLED | KN_QUEUED)) == KN_ACTIVE) knote_enqueue(kn); kn->kn_status &= ~KN_SCAN; kn_leave_flux(kn); kn_list_unlock(knl); KQ_UNLOCK_FLUX(kq); done: KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal); if (filedesc_unlock) FILEDESC_XUNLOCK(td->td_proc->p_fd); if (fp != NULL) fdrop(fp, td); knote_free(tkn); if (fops != NULL) kqueue_fo_release(filt); return (error); } static int kqueue_acquire(struct file *fp, struct kqueue **kqp) { int error; struct kqueue *kq; error = 0; kq = fp->f_data; if (fp->f_type != DTYPE_KQUEUE || kq == NULL) return (EBADF); *kqp = kq; KQ_LOCK(kq); if ((kq->kq_state & KQ_CLOSING) == KQ_CLOSING) { KQ_UNLOCK(kq); return (EBADF); } kq->kq_refcnt++; KQ_UNLOCK(kq); return error; } static void kqueue_release(struct kqueue *kq, int locked) { if (locked) KQ_OWNED(kq); else KQ_LOCK(kq); kq->kq_refcnt--; if (kq->kq_refcnt == 1) wakeup(&kq->kq_refcnt); if (!locked) KQ_UNLOCK(kq); } static void ast_kqueue(struct thread *td, int tda __unused) { taskqueue_quiesce(taskqueue_kqueue_ctx); } static void kqueue_schedtask(struct kqueue *kq) { KQ_OWNED(kq); KASSERT(((kq->kq_state & KQ_TASKDRAIN) != KQ_TASKDRAIN), ("scheduling kqueue task while draining")); if ((kq->kq_state & KQ_TASKSCHED) != KQ_TASKSCHED) { taskqueue_enqueue(taskqueue_kqueue_ctx, &kq->kq_task); kq->kq_state |= KQ_TASKSCHED; ast_sched(curthread, TDA_KQUEUE); } } /* * Expand the kq to make sure we have storage for fops/ident pair. * * Return 0 on success (or no work necessary), return errno on failure. */ static int kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident, int mflag) { struct klist *list, *tmp_knhash, *to_free; u_long tmp_knhashmask; int error, fd, size; KQ_NOTOWNED(kq); error = 0; to_free = NULL; if (fops->f_isfd) { fd = ident; if (kq->kq_knlistsize <= fd) { size = kq->kq_knlistsize; while (size <= fd) size += KQEXTENT; list = malloc(size * sizeof(*list), M_KQUEUE, mflag); if (list == NULL) return ENOMEM; KQ_LOCK(kq); if ((kq->kq_state & KQ_CLOSING) != 0) { to_free = list; error = EBADF; } else if (kq->kq_knlistsize > fd) { to_free = list; } else { if (kq->kq_knlist != NULL) { bcopy(kq->kq_knlist, list, kq->kq_knlistsize * sizeof(*list)); to_free = kq->kq_knlist; kq->kq_knlist = NULL; } bzero((caddr_t)list + kq->kq_knlistsize * sizeof(*list), (size - kq->kq_knlistsize) * sizeof(*list)); kq->kq_knlistsize = size; kq->kq_knlist = list; } KQ_UNLOCK(kq); } } else { if (kq->kq_knhashmask == 0) { tmp_knhash = hashinit_flags(KN_HASHSIZE, M_KQUEUE, &tmp_knhashmask, (mflag & M_WAITOK) != 0 ? HASH_WAITOK : HASH_NOWAIT); if (tmp_knhash == NULL) return (ENOMEM); KQ_LOCK(kq); if ((kq->kq_state & KQ_CLOSING) != 0) { to_free = tmp_knhash; error = EBADF; } else if (kq->kq_knhashmask == 0) { kq->kq_knhash = tmp_knhash; kq->kq_knhashmask = tmp_knhashmask; } else { to_free = tmp_knhash; } KQ_UNLOCK(kq); } } free(to_free, M_KQUEUE); KQ_NOTOWNED(kq); return (error); } static void kqueue_task(void *arg, int pending) { struct kqueue *kq; int haskqglobal; haskqglobal = 0; kq = arg; KQ_GLOBAL_LOCK(&kq_global, haskqglobal); KQ_LOCK(kq); KNOTE_LOCKED(&kq->kq_sel.si_note, 0); kq->kq_state &= ~KQ_TASKSCHED; if ((kq->kq_state & KQ_TASKDRAIN) == KQ_TASKDRAIN) { wakeup(&kq->kq_state); } KQ_UNLOCK(kq); KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal); } /* * Scan, update kn_data (if not ONESHOT), and copyout triggered events. * We treat KN_MARKER knotes as if they are in flux. */ static int kqueue_scan(struct kqueue *kq, int maxevents, struct kevent_copyops *k_ops, const struct timespec *tsp, struct kevent *keva, struct thread *td) { struct kevent *kevp; struct knote *kn, *marker; struct knlist *knl; sbintime_t asbt, rsbt; int count, error, haskqglobal, influx, nkev, touch; count = maxevents; nkev = 0; error = 0; haskqglobal = 0; if (maxevents == 0) goto done_nl; if (maxevents < 0) { error = EINVAL; goto done_nl; } rsbt = 0; if (tsp != NULL) { if (!timespecvalid_interval(tsp)) { error = EINVAL; goto done_nl; } if (timespecisset(tsp)) { if (tsp->tv_sec <= INT32_MAX) { rsbt = tstosbt(*tsp); if (TIMESEL(&asbt, rsbt)) asbt += tc_tick_sbt; if (asbt <= SBT_MAX - rsbt) asbt += rsbt; else asbt = 0; rsbt >>= tc_precexp; } else asbt = 0; } else asbt = -1; } else asbt = 0; marker = knote_alloc(M_WAITOK); marker->kn_status = KN_MARKER; KQ_LOCK(kq); retry: kevp = keva; if (kq->kq_count == 0) { if (asbt == -1) { error = EWOULDBLOCK; } else { kq->kq_state |= KQ_SLEEP; error = msleep_sbt(kq, &kq->kq_lock, PSOCK | PCATCH, "kqread", asbt, rsbt, C_ABSOLUTE); } if (error == 0) goto retry; /* don't restart after signals... */ if (error == ERESTART) error = EINTR; else if (error == EWOULDBLOCK) error = 0; goto done; } TAILQ_INSERT_TAIL(&kq->kq_head, marker, kn_tqe); influx = 0; while (count) { KQ_OWNED(kq); kn = TAILQ_FIRST(&kq->kq_head); if ((kn->kn_status == KN_MARKER && kn != marker) || kn_in_flux(kn)) { if (influx) { influx = 0; KQ_FLUX_WAKEUP(kq); } kq->kq_state |= KQ_FLUXWAIT; error = msleep(kq, &kq->kq_lock, PSOCK, "kqflxwt", 0); continue; } TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe); if ((kn->kn_status & KN_DISABLED) == KN_DISABLED) { kn->kn_status &= ~KN_QUEUED; kq->kq_count--; continue; } if (kn == marker) { KQ_FLUX_WAKEUP(kq); if (count == maxevents) goto retry; goto done; } KASSERT(!kn_in_flux(kn), ("knote %p is unexpectedly in flux", kn)); if ((kn->kn_flags & EV_DROP) == EV_DROP) { kn->kn_status &= ~KN_QUEUED; kn_enter_flux(kn); kq->kq_count--; KQ_UNLOCK(kq); /* * We don't need to lock the list since we've * marked it as in flux. */ knote_drop(kn, td); KQ_LOCK(kq); continue; } else if ((kn->kn_flags & EV_ONESHOT) == EV_ONESHOT) { kn->kn_status &= ~KN_QUEUED; kn_enter_flux(kn); kq->kq_count--; KQ_UNLOCK(kq); /* * We don't need to lock the list since we've * marked the knote as being in flux. */ *kevp = kn->kn_kevent; knote_drop(kn, td); KQ_LOCK(kq); kn = NULL; } else { kn->kn_status |= KN_SCAN; kn_enter_flux(kn); KQ_UNLOCK(kq); if ((kn->kn_status & KN_KQUEUE) == KN_KQUEUE) KQ_GLOBAL_LOCK(&kq_global, haskqglobal); knl = kn_list_lock(kn); if (kn->kn_fop->f_event(kn, 0) == 0) { KQ_LOCK(kq); KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal); kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE | KN_SCAN); kn_leave_flux(kn); kq->kq_count--; kn_list_unlock(knl); influx = 1; continue; } touch = (!kn->kn_fop->f_isfd && kn->kn_fop->f_touch != NULL); if (touch) kn->kn_fop->f_touch(kn, kevp, EVENT_PROCESS); else *kevp = kn->kn_kevent; KQ_LOCK(kq); KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal); if (kn->kn_flags & (EV_CLEAR | EV_DISPATCH)) { /* * Manually clear knotes who weren't * 'touch'ed. */ if (touch == 0 && kn->kn_flags & EV_CLEAR) { kn->kn_data = 0; kn->kn_fflags = 0; } if (kn->kn_flags & EV_DISPATCH) kn->kn_status |= KN_DISABLED; kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE); kq->kq_count--; } else TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe); kn->kn_status &= ~KN_SCAN; kn_leave_flux(kn); kn_list_unlock(knl); influx = 1; } /* we are returning a copy to the user */ kevp++; nkev++; count--; if (nkev == KQ_NEVENTS) { influx = 0; KQ_UNLOCK_FLUX(kq); error = k_ops->k_copyout(k_ops->arg, keva, nkev); nkev = 0; kevp = keva; KQ_LOCK(kq); if (error) break; } } TAILQ_REMOVE(&kq->kq_head, marker, kn_tqe); done: KQ_OWNED(kq); KQ_UNLOCK_FLUX(kq); knote_free(marker); done_nl: KQ_NOTOWNED(kq); if (nkev != 0) error = k_ops->k_copyout(k_ops->arg, keva, nkev); td->td_retval[0] = maxevents - count; return (error); } /*ARGSUSED*/ static int kqueue_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred, struct thread *td) { /* * Enabling sigio causes two major problems: * 1) infinite recursion: * Synopsys: kevent is being used to track signals and have FIOASYNC * set. On receipt of a signal this will cause a kqueue to recurse * into itself over and over. Sending the sigio causes the kqueue * to become ready, which in turn posts sigio again, forever. * Solution: this can be solved by setting a flag in the kqueue that * we have a SIGIO in progress. * 2) locking problems: * Synopsys: Kqueue is a leaf subsystem, but adding signalling puts * us above the proc and pgrp locks. * Solution: Post a signal using an async mechanism, being sure to * record a generation count in the delivery so that we do not deliver * a signal to the wrong process. * * Note, these two mechanisms are somewhat mutually exclusive! */ #if 0 struct kqueue *kq; kq = fp->f_data; switch (cmd) { case FIOASYNC: if (*(int *)data) { kq->kq_state |= KQ_ASYNC; } else { kq->kq_state &= ~KQ_ASYNC; } return (0); case FIOSETOWN: return (fsetown(*(int *)data, &kq->kq_sigio)); case FIOGETOWN: *(int *)data = fgetown(&kq->kq_sigio); return (0); } #endif return (ENOTTY); } /*ARGSUSED*/ static int kqueue_poll(struct file *fp, int events, struct ucred *active_cred, struct thread *td) { struct kqueue *kq; int revents = 0; int error; if ((error = kqueue_acquire(fp, &kq))) return POLLERR; KQ_LOCK(kq); if (events & (POLLIN | POLLRDNORM)) { if (kq->kq_count) { revents |= events & (POLLIN | POLLRDNORM); } else { selrecord(td, &kq->kq_sel); if (SEL_WAITING(&kq->kq_sel)) kq->kq_state |= KQ_SEL; } } kqueue_release(kq, 1); KQ_UNLOCK(kq); return (revents); } /*ARGSUSED*/ static int kqueue_stat(struct file *fp, struct stat *st, struct ucred *active_cred) { bzero((void *)st, sizeof *st); /* * We no longer return kq_count because the unlocked value is useless. * If you spent all this time getting the count, why not spend your * syscall better by calling kevent? * * XXX - This is needed for libc_r. */ st->st_mode = S_IFIFO; return (0); } static void kqueue_drain(struct kqueue *kq, struct thread *td) { struct knote *kn; int i; KQ_LOCK(kq); KASSERT((kq->kq_state & KQ_CLOSING) != KQ_CLOSING, ("kqueue already closing")); kq->kq_state |= KQ_CLOSING; if (kq->kq_refcnt > 1) msleep(&kq->kq_refcnt, &kq->kq_lock, PSOCK, "kqclose", 0); KASSERT(kq->kq_refcnt == 1, ("other refs are out there!")); KASSERT(knlist_empty(&kq->kq_sel.si_note), ("kqueue's knlist not empty")); for (i = 0; i < kq->kq_knlistsize; i++) { while ((kn = SLIST_FIRST(&kq->kq_knlist[i])) != NULL) { if (kn_in_flux(kn)) { kq->kq_state |= KQ_FLUXWAIT; msleep(kq, &kq->kq_lock, PSOCK, "kqclo1", 0); continue; } kn_enter_flux(kn); KQ_UNLOCK(kq); knote_drop(kn, td); KQ_LOCK(kq); } } if (kq->kq_knhashmask != 0) { for (i = 0; i <= kq->kq_knhashmask; i++) { while ((kn = SLIST_FIRST(&kq->kq_knhash[i])) != NULL) { if (kn_in_flux(kn)) { kq->kq_state |= KQ_FLUXWAIT; msleep(kq, &kq->kq_lock, PSOCK, "kqclo2", 0); continue; } kn_enter_flux(kn); KQ_UNLOCK(kq); knote_drop(kn, td); KQ_LOCK(kq); } } } if ((kq->kq_state & KQ_TASKSCHED) == KQ_TASKSCHED) { kq->kq_state |= KQ_TASKDRAIN; msleep(&kq->kq_state, &kq->kq_lock, PSOCK, "kqtqdr", 0); } if ((kq->kq_state & KQ_SEL) == KQ_SEL) { selwakeuppri(&kq->kq_sel, PSOCK); if (!SEL_WAITING(&kq->kq_sel)) kq->kq_state &= ~KQ_SEL; } KQ_UNLOCK(kq); } static void kqueue_destroy(struct kqueue *kq) { KASSERT(kq->kq_fdp == NULL, ("kqueue still attached to a file descriptor")); seldrain(&kq->kq_sel); knlist_destroy(&kq->kq_sel.si_note); mtx_destroy(&kq->kq_lock); if (kq->kq_knhash != NULL) free(kq->kq_knhash, M_KQUEUE); if (kq->kq_knlist != NULL) free(kq->kq_knlist, M_KQUEUE); funsetown(&kq->kq_sigio); } /*ARGSUSED*/ static int kqueue_close(struct file *fp, struct thread *td) { struct kqueue *kq = fp->f_data; struct filedesc *fdp; int error; int filedesc_unlock; if ((error = kqueue_acquire(fp, &kq))) return error; kqueue_drain(kq, td); /* * We could be called due to the knote_drop() doing fdrop(), * called from kqueue_register(). In this case the global * lock is owned, and filedesc sx is locked before, to not * take the sleepable lock after non-sleepable. */ fdp = kq->kq_fdp; kq->kq_fdp = NULL; if (!sx_xlocked(FILEDESC_LOCK(fdp))) { FILEDESC_XLOCK(fdp); filedesc_unlock = 1; } else filedesc_unlock = 0; TAILQ_REMOVE(&fdp->fd_kqlist, kq, kq_list); if (filedesc_unlock) FILEDESC_XUNLOCK(fdp); kqueue_destroy(kq); chgkqcnt(kq->kq_cred->cr_ruidinfo, -1, 0); crfree(kq->kq_cred); free(kq, M_KQUEUE); fp->f_data = NULL; return (0); } static int kqueue_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) { struct kqueue *kq = fp->f_data; kif->kf_type = KF_TYPE_KQUEUE; kif->kf_un.kf_kqueue.kf_kqueue_addr = (uintptr_t)kq; kif->kf_un.kf_kqueue.kf_kqueue_count = kq->kq_count; kif->kf_un.kf_kqueue.kf_kqueue_state = kq->kq_state; return (0); } static void kqueue_wakeup(struct kqueue *kq) { KQ_OWNED(kq); if ((kq->kq_state & KQ_SLEEP) == KQ_SLEEP) { kq->kq_state &= ~KQ_SLEEP; wakeup(kq); } if ((kq->kq_state & KQ_SEL) == KQ_SEL) { selwakeuppri(&kq->kq_sel, PSOCK); if (!SEL_WAITING(&kq->kq_sel)) kq->kq_state &= ~KQ_SEL; } if (!knlist_empty(&kq->kq_sel.si_note)) kqueue_schedtask(kq); if ((kq->kq_state & KQ_ASYNC) == KQ_ASYNC) { pgsigio(&kq->kq_sigio, SIGIO, 0); } } /* * Walk down a list of knotes, activating them if their event has triggered. * * There is a possibility to optimize in the case of one kq watching another. * Instead of scheduling a task to wake it up, you could pass enough state * down the chain to make up the parent kqueue. Make this code functional * first. */ void knote(struct knlist *list, long hint, int lockflags) { struct kqueue *kq; struct knote *kn, *tkn; int error; if (list == NULL) return; KNL_ASSERT_LOCK(list, lockflags & KNF_LISTLOCKED); if ((lockflags & KNF_LISTLOCKED) == 0) list->kl_lock(list->kl_lockarg); /* * If we unlock the list lock (and enter influx), we can * eliminate the kqueue scheduling, but this will introduce * four lock/unlock's for each knote to test. Also, marker * would be needed to keep iteration position, since filters * or other threads could remove events. */ SLIST_FOREACH_SAFE(kn, &list->kl_list, kn_selnext, tkn) { kq = kn->kn_kq; KQ_LOCK(kq); if (kn_in_flux(kn) && (kn->kn_status & KN_SCAN) == 0) { /* * Do not process the influx notes, except for * the influx coming from the kq unlock in the * kqueue_scan(). In the later case, we do * not interfere with the scan, since the code * fragment in kqueue_scan() locks the knlist, * and cannot proceed until we finished. */ KQ_UNLOCK(kq); } else if ((lockflags & KNF_NOKQLOCK) != 0) { kn_enter_flux(kn); KQ_UNLOCK(kq); error = kn->kn_fop->f_event(kn, hint); KQ_LOCK(kq); kn_leave_flux(kn); if (error) KNOTE_ACTIVATE(kn, 1); KQ_UNLOCK_FLUX(kq); } else { if (kn->kn_fop->f_event(kn, hint)) KNOTE_ACTIVATE(kn, 1); KQ_UNLOCK(kq); } } if ((lockflags & KNF_LISTLOCKED) == 0) list->kl_unlock(list->kl_lockarg); } /* * add a knote to a knlist */ void knlist_add(struct knlist *knl, struct knote *kn, int islocked) { KNL_ASSERT_LOCK(knl, islocked); KQ_NOTOWNED(kn->kn_kq); KASSERT(kn_in_flux(kn), ("knote %p not in flux", kn)); KASSERT((kn->kn_status & KN_DETACHED) != 0, ("knote %p was not detached", kn)); if (!islocked) knl->kl_lock(knl->kl_lockarg); SLIST_INSERT_HEAD(&knl->kl_list, kn, kn_selnext); if (!islocked) knl->kl_unlock(knl->kl_lockarg); KQ_LOCK(kn->kn_kq); kn->kn_knlist = knl; kn->kn_status &= ~KN_DETACHED; KQ_UNLOCK(kn->kn_kq); } static void knlist_remove_kq(struct knlist *knl, struct knote *kn, int knlislocked, int kqislocked) { KASSERT(!kqislocked || knlislocked, ("kq locked w/o knl locked")); KNL_ASSERT_LOCK(knl, knlislocked); mtx_assert(&kn->kn_kq->kq_lock, kqislocked ? MA_OWNED : MA_NOTOWNED); KASSERT(kqislocked || kn_in_flux(kn), ("knote %p not in flux", kn)); KASSERT((kn->kn_status & KN_DETACHED) == 0, ("knote %p was already detached", kn)); if (!knlislocked) knl->kl_lock(knl->kl_lockarg); SLIST_REMOVE(&knl->kl_list, kn, knote, kn_selnext); kn->kn_knlist = NULL; if (!knlislocked) kn_list_unlock(knl); if (!kqislocked) KQ_LOCK(kn->kn_kq); kn->kn_status |= KN_DETACHED; if (!kqislocked) KQ_UNLOCK(kn->kn_kq); } /* * remove knote from the specified knlist */ void knlist_remove(struct knlist *knl, struct knote *kn, int islocked) { knlist_remove_kq(knl, kn, islocked, 0); } int knlist_empty(struct knlist *knl) { KNL_ASSERT_LOCKED(knl); return (SLIST_EMPTY(&knl->kl_list)); } static struct mtx knlist_lock; MTX_SYSINIT(knlist_lock, &knlist_lock, "knlist lock for lockless objects", MTX_DEF); static void knlist_mtx_lock(void *arg); static void knlist_mtx_unlock(void *arg); static void knlist_mtx_lock(void *arg) { mtx_lock((struct mtx *)arg); } static void knlist_mtx_unlock(void *arg) { mtx_unlock((struct mtx *)arg); } static void knlist_mtx_assert_lock(void *arg, int what) { if (what == LA_LOCKED) mtx_assert((struct mtx *)arg, MA_OWNED); else mtx_assert((struct mtx *)arg, MA_NOTOWNED); } void knlist_init(struct knlist *knl, void *lock, void (*kl_lock)(void *), void (*kl_unlock)(void *), void (*kl_assert_lock)(void *, int)) { if (lock == NULL) knl->kl_lockarg = &knlist_lock; else knl->kl_lockarg = lock; if (kl_lock == NULL) knl->kl_lock = knlist_mtx_lock; else knl->kl_lock = kl_lock; if (kl_unlock == NULL) knl->kl_unlock = knlist_mtx_unlock; else knl->kl_unlock = kl_unlock; if (kl_assert_lock == NULL) knl->kl_assert_lock = knlist_mtx_assert_lock; else knl->kl_assert_lock = kl_assert_lock; knl->kl_autodestroy = 0; SLIST_INIT(&knl->kl_list); } void knlist_init_mtx(struct knlist *knl, struct mtx *lock) { knlist_init(knl, lock, NULL, NULL, NULL); } struct knlist * knlist_alloc(struct mtx *lock) { struct knlist *knl; knl = malloc(sizeof(struct knlist), M_KQUEUE, M_WAITOK); knlist_init_mtx(knl, lock); return (knl); } void knlist_destroy(struct knlist *knl) { KASSERT(KNLIST_EMPTY(knl), ("destroying knlist %p with knotes on it", knl)); } void knlist_detach(struct knlist *knl) { KNL_ASSERT_LOCKED(knl); knl->kl_autodestroy = 1; if (knlist_empty(knl)) { knlist_destroy(knl); free(knl, M_KQUEUE); } } /* * Even if we are locked, we may need to drop the lock to allow any influx * knotes time to "settle". */ void knlist_cleardel(struct knlist *knl, struct thread *td, int islocked, int killkn) { struct knote *kn, *kn2; struct kqueue *kq; KASSERT(!knl->kl_autodestroy, ("cleardel for autodestroy %p", knl)); if (islocked) KNL_ASSERT_LOCKED(knl); else { KNL_ASSERT_UNLOCKED(knl); again: /* need to reacquire lock since we have dropped it */ knl->kl_lock(knl->kl_lockarg); } SLIST_FOREACH_SAFE(kn, &knl->kl_list, kn_selnext, kn2) { kq = kn->kn_kq; KQ_LOCK(kq); if (kn_in_flux(kn)) { KQ_UNLOCK(kq); continue; } knlist_remove_kq(knl, kn, 1, 1); if (killkn) { kn_enter_flux(kn); KQ_UNLOCK(kq); knote_drop_detached(kn, td); } else { /* Make sure cleared knotes disappear soon */ kn->kn_flags |= EV_EOF | EV_ONESHOT; KQ_UNLOCK(kq); } kq = NULL; } if (!SLIST_EMPTY(&knl->kl_list)) { /* there are still in flux knotes remaining */ kn = SLIST_FIRST(&knl->kl_list); kq = kn->kn_kq; KQ_LOCK(kq); KASSERT(kn_in_flux(kn), ("knote removed w/o list lock")); knl->kl_unlock(knl->kl_lockarg); kq->kq_state |= KQ_FLUXWAIT; msleep(kq, &kq->kq_lock, PSOCK | PDROP, "kqkclr", 0); kq = NULL; goto again; } if (islocked) KNL_ASSERT_LOCKED(knl); else { knl->kl_unlock(knl->kl_lockarg); KNL_ASSERT_UNLOCKED(knl); } } /* * Remove all knotes referencing a specified fd must be called with FILEDESC * lock. This prevents a race where a new fd comes along and occupies the * entry and we attach a knote to the fd. */ void knote_fdclose(struct thread *td, int fd) { struct filedesc *fdp = td->td_proc->p_fd; struct kqueue *kq; struct knote *kn; int influx; FILEDESC_XLOCK_ASSERT(fdp); /* * We shouldn't have to worry about new kevents appearing on fd * since filedesc is locked. */ TAILQ_FOREACH(kq, &fdp->fd_kqlist, kq_list) { KQ_LOCK(kq); again: influx = 0; while (kq->kq_knlistsize > fd && (kn = SLIST_FIRST(&kq->kq_knlist[fd])) != NULL) { if (kn_in_flux(kn)) { /* someone else might be waiting on our knote */ if (influx) wakeup(kq); kq->kq_state |= KQ_FLUXWAIT; msleep(kq, &kq->kq_lock, PSOCK, "kqflxwt", 0); goto again; } kn_enter_flux(kn); KQ_UNLOCK(kq); influx = 1; knote_drop(kn, td); KQ_LOCK(kq); } KQ_UNLOCK_FLUX(kq); } } static int knote_attach(struct knote *kn, struct kqueue *kq) { struct klist *list; KASSERT(kn_in_flux(kn), ("knote %p not marked influx", kn)); KQ_OWNED(kq); if ((kq->kq_state & KQ_CLOSING) != 0) return (EBADF); if (kn->kn_fop->f_isfd) { if (kn->kn_id >= kq->kq_knlistsize) return (ENOMEM); list = &kq->kq_knlist[kn->kn_id]; } else { if (kq->kq_knhash == NULL) return (ENOMEM); list = &kq->kq_knhash[KN_HASH(kn->kn_id, kq->kq_knhashmask)]; } SLIST_INSERT_HEAD(list, kn, kn_link); return (0); } static void knote_drop(struct knote *kn, struct thread *td) { if ((kn->kn_status & KN_DETACHED) == 0) kn->kn_fop->f_detach(kn); knote_drop_detached(kn, td); } static void knote_drop_detached(struct knote *kn, struct thread *td) { struct kqueue *kq; struct klist *list; kq = kn->kn_kq; KASSERT((kn->kn_status & KN_DETACHED) != 0, ("knote %p still attached", kn)); KQ_NOTOWNED(kq); KQ_LOCK(kq); KASSERT(kn->kn_influx == 1, ("knote_drop called on %p with influx %d", kn, kn->kn_influx)); if (kn->kn_fop->f_isfd) list = &kq->kq_knlist[kn->kn_id]; else list = &kq->kq_knhash[KN_HASH(kn->kn_id, kq->kq_knhashmask)]; if (!SLIST_EMPTY(list)) SLIST_REMOVE(list, kn, knote, kn_link); if (kn->kn_status & KN_QUEUED) knote_dequeue(kn); KQ_UNLOCK_FLUX(kq); if (kn->kn_fop->f_isfd) { fdrop(kn->kn_fp, td); kn->kn_fp = NULL; } kqueue_fo_release(kn->kn_kevent.filter); kn->kn_fop = NULL; knote_free(kn); } static void knote_enqueue(struct knote *kn) { struct kqueue *kq = kn->kn_kq; KQ_OWNED(kn->kn_kq); KASSERT((kn->kn_status & KN_QUEUED) == 0, ("knote already queued")); TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe); kn->kn_status |= KN_QUEUED; kq->kq_count++; kqueue_wakeup(kq); } static void knote_dequeue(struct knote *kn) { struct kqueue *kq = kn->kn_kq; KQ_OWNED(kn->kn_kq); KASSERT(kn->kn_status & KN_QUEUED, ("knote not queued")); TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe); kn->kn_status &= ~KN_QUEUED; kq->kq_count--; } static void knote_init(void) { knote_zone = uma_zcreate("KNOTE", sizeof(struct knote), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); ast_register(TDA_KQUEUE, ASTR_ASTF_REQUIRED, 0, ast_kqueue); } SYSINIT(knote, SI_SUB_PSEUDO, SI_ORDER_ANY, knote_init, NULL); static struct knote * knote_alloc(int mflag) { return (uma_zalloc(knote_zone, mflag | M_ZERO)); } static void knote_free(struct knote *kn) { uma_zfree(knote_zone, kn); } /* * Register the kev w/ the kq specified by fd. */ int kqfd_register(int fd, struct kevent *kev, struct thread *td, int mflag) { struct kqueue *kq; struct file *fp; cap_rights_t rights; int error; error = fget(td, fd, cap_rights_init_one(&rights, CAP_KQUEUE_CHANGE), &fp); if (error != 0) return (error); if ((error = kqueue_acquire(fp, &kq)) != 0) goto noacquire; error = kqueue_register(kq, kev, td, mflag); kqueue_release(kq, 0); noacquire: fdrop(fp, td); return (error); } diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 52ae6bda5a16..92de51fc0d97 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,3315 +1,3315 @@ $FreeBSD$ ; from: @(#)syscalls.master 8.2 (Berkeley) 1/13/94 ; ; System call name/number master file. ; Processed to created init_sysent.c, syscalls.c and syscall.h. ; New FreeBSD system calls should be added to the bottom of this file. ; Columns: number audit type name alt{name,tag,rtyp}/comments ; number system call number, must be in order ; audit the audit event associated with the system call ; A value of AUE_NULL means no auditing, but it also means that ; there is no audit event for the call at this time. For the ; case where the event exists, but we don't want auditing, the ; event should be #defined to AUE_NULL in audit_kevents.h. ; type one of STD, OBSOL, RESERVED, UNIMPL, SYSMUX, COMPAT*, ; NODEF, NOARGS, NOPROTO, NOSTD ; The COMPAT* options may be combined with one or more NO* ; options separated by '|' with no spaces (e.g. COMPAT|NOARGS) ; The CAPENABLED option may be ORed into a type. ; name pseudo-prototype of syscall routine ; If one of the following alts is different, then all appear: ; altname name of system call if different ; alttag name of args struct tag if different from [o]`name'"_args" ; altrtyp return type if not int (bogus - syscalls always return int) ; for UNIMPL/OBSOL, name continues with comments ; types: ; STD always included ; COMPAT included on COMPAT #ifdef ; COMPAT4 included on COMPAT_FREEBSD4 #ifdef (FreeBSD 4 compat) ; COMPAT6 included on COMPAT_FREEBSD6 #ifdef (FreeBSD 6 compat) ; COMPAT7 included on COMPAT_FREEBSD7 #ifdef (FreeBSD 7 compat) ; COMPAT10 included on COMPAT_FREEBSD10 #ifdef (FreeBSD 10 compat) ; COMPAT11 included on COMPAT_FREEBSD11 #ifdef (FreeBSD 11 compat) ; COMPAT12 included on COMPAT_FREEBSD12 #ifdef (FreeBSD 12 compat) ; COMPAT13 included on COMPAT_FREEBSD13 #ifdef (FreeBSD 13 compat) ; OBSOL obsolete, not included in system, only specifies name ; RESERVED reserved for local or vendor use (not for FreeBSD) ; UNIMPL not implemented, placeholder only ; NOSTD implemented but as a lkm that can be statically ; compiled in; sysent entry will be filled with lkmressys ; so the SYSCALL_MODULE macro works ; NOARGS same as STD except do not create structure in sys/sysproto.h ; NODEF same as STD except only have the entry in the syscall table ; added. Meaning - do not create structure or function ; prototype in sys/sysproto.h ; NOPROTO same as STD except do not create structure or ; function prototype in sys/sysproto.h. Does add a ; definition to syscall.h besides adding a sysent. ; NOTSTATIC syscall is loadable ; SYSMUX syscall multiplexer. No prototype, argument struct, or ; handler is declared or used. Handled in MD syscall code. ; CAPENABLED syscall is allowed in capability mode ; ; To support programmatic generation of both the default ABI and 32-bit compat ; (freebsd32) we impose a number of restrictions on the types of system calls. ; For integer types: ; - Bare int and long are allowed (long is a sign of a bad interface). ; - Use u_int and u_long rather than "unsigned (int|long)". ; - size_t is allowed. ; - typedefs are allowed, but new signed types that vary between 32- and ; 64-bit ABIs must be added to makesyscalls.lua so it knows they require ; handling. ; - Always-64-bit types other than dev_t, id_t, and off_t must be added to ; makesyscalls.lua. ; For pointers: ; - Prefer structs to typedefs so an ABI-specific suffix (e.g., "32") can ; be prepended (e.g., ucontext_t -> struct ucontext -> struct ucontext32). ; - Pointers to objects (structs, unions, etc) containing any long, pointer, ; or time_t arguments need _Contains_ annotations. Such objects should be ; padded such that all 64-bit types are 64-bit aligned. ; annotations: ; SAL 2.0 annotations are used to specify how system calls treat ; arguments that are passed using pointers. There are three basic ; annotations. ; ; _In_ Object pointed to will be read and not modified. ; _Out_ Object pointed to will be written and not read. ; _Inout_ Object pointed to will be written and read. ; ; These annotations are used alone when the pointer refers to a single ; object i.e. scalar types, structs, and pointers, and not NULL. Adding ; the _opt_ suffix, e.g. _In_opt_, implies that the pointer may also ; refer to NULL. ; ; For pointers to arrays, additional suffixes are added: ; ; _In_z_, _Out_z_, _Inout_z_: ; for a NUL terminated array e.g. a string. ; _In_reads_z_(n),_Out_writes_z_(n), _Inout_updates_z_(n): ; for a NUL terminated array e.g. a string, of known length n bytes. ; _In_reads_(n),_Out_writes_(n),_Inout_updates_(n): ; for an array of n elements. ; _In_reads_bytes_(n), _Out_writes_bytes_(n), _Inout_updates_bytes(n): ; for a buffer of n-bytes. ; ; In addition to SAL annotations, pointers are annotated to indicate ; that they point to types that change between ABIs. That means that ; they contain long, pointer, or time_t types. This is indicated with ; a _Contains_ annotation followed immediately by one or more of: ; ; long_ Object contains a direct (or typedef'd) long value and varies ; between 32- and 64-bit ABIs. This includes size_t. ; ptr_ Object contains pointers (or intptr_t) and varies between ; 32- and 64-bit ABIs. ; timet_ Object contains a time_t and varies between i386 and other ; ABIs. ; #ifdef's, etc. may be included, and are copied to the output files. #include #include #include %%ABI_HEADERS%% 0 AUE_NULL SYSMUX { int syscall( int number, ... ); } 1 AUE_EXIT STD|CAPENABLED { void exit( int rval ); } 2 AUE_FORK STD|CAPENABLED { int fork(void); } 3 AUE_READ STD|CAPENABLED { ssize_t read( int fd, _Out_writes_bytes_(nbyte) void *buf, size_t nbyte ); } 4 AUE_WRITE STD|CAPENABLED { ssize_t write( int fd, _In_reads_bytes_(nbyte) const void *buf, size_t nbyte ); } 5 AUE_OPEN_RWTC STD { int open( _In_z_ const char *path, int flags, mode_t mode ); } ; XXX should be { int open(const char *path, int flags, ...); } ; but we're not ready for varargs. 6 AUE_CLOSE STD|CAPENABLED { int close( int fd ); } 7 AUE_WAIT4 STD { int wait4( int pid, _Out_opt_ int *status, int options, _Out_opt_ _Contains_long_timet_ struct rusage *rusage ); } 8 AUE_CREAT COMPAT { int creat( _In_z_ const char *path, int mode ); } 9 AUE_LINK STD { int link( _In_z_ const char *path, _In_z_ const char *link ); } 10 AUE_UNLINK STD { int unlink( _In_z_ const char *path ); } 11 AUE_NULL OBSOL execv 12 AUE_CHDIR STD { int chdir( _In_z_ const char *path ); } 13 AUE_FCHDIR STD { int fchdir( int fd ); } 14 AUE_MKNOD COMPAT11 { int mknod( _In_z_ const char *path, int mode, uint32_t dev ); } 15 AUE_CHMOD STD { int chmod( _In_z_ const char *path, mode_t mode ); } 16 AUE_CHOWN STD { int chown( _In_z_ const char *path, int uid, int gid ); } 17 AUE_NULL STD|CAPENABLED { void *break( _In_ char *nsize ); } 18 AUE_GETFSSTAT COMPAT4 { int getfsstat( _Out_writes_bytes_opt_(bufsize) _Contains_long_ struct ostatfs *buf, long bufsize, int mode ); } 19 AUE_LSEEK COMPAT|CAPENABLED { long lseek( int fd, long offset, int whence ); } 20 AUE_GETPID STD|CAPENABLED { pid_t getpid(void); } 21 AUE_MOUNT STD { int mount( _In_z_ const char *type, _In_z_ const char *path, int flags, _In_opt_ void *data ); } 22 AUE_UMOUNT STD { int unmount( _In_z_ const char *path, int flags ); } 23 AUE_SETUID STD|CAPENABLED { int setuid( uid_t uid ); } 24 AUE_GETUID STD|CAPENABLED { uid_t getuid(void); } 25 AUE_GETEUID STD|CAPENABLED { uid_t geteuid(void); } 26 AUE_PTRACE STD { int ptrace( int req, pid_t pid, _Inout_opt_ _Contains_long_ptr_ caddr_t addr, int data ); } 27 AUE_RECVMSG STD|CAPENABLED { ssize_t recvmsg( int s, _Inout_ _Contains_ptr_ struct msghdr *msg, int flags ); } 28 AUE_SENDMSG STD|CAPENABLED { ssize_t sendmsg( int s, _In_ _Contains_ptr_ const struct msghdr *msg, int flags ); } 29 AUE_RECVFROM STD|CAPENABLED { ssize_t recvfrom( int s, _Out_writes_bytes_(len) void *buf, size_t len, int flags, _Out_writes_bytes_opt_(*fromlenaddr) struct sockaddr *from, _Inout_opt_ __socklen_t *fromlenaddr ); } 30 AUE_ACCEPT STD|CAPENABLED { int accept( int s, _Out_writes_bytes_opt_(*anamelen) struct sockaddr *name, _Inout_opt_ __socklen_t *anamelen ); } 31 AUE_GETPEERNAME STD|CAPENABLED { int getpeername( int fdes, _Out_writes_bytes_(*alen) struct sockaddr *asa, _Inout_opt_ __socklen_t *alen ); } 32 AUE_GETSOCKNAME STD|CAPENABLED { int getsockname( int fdes, _Out_writes_bytes_(*alen) struct sockaddr *asa, _Inout_ __socklen_t *alen ); } 33 AUE_ACCESS STD { int access( _In_z_ const char *path, int amode ); } 34 AUE_CHFLAGS STD { int chflags( _In_z_ const char *path, u_long flags ); } 35 AUE_FCHFLAGS STD|CAPENABLED { int fchflags( int fd, u_long flags ); } 36 AUE_SYNC STD|CAPENABLED { int sync(void); } 37 AUE_KILL STD|CAPENABLED { int kill( int pid, int signum ); } 38 AUE_STAT COMPAT { int stat( _In_z_ const char *path, _Out_ _Contains_timet_ struct ostat *ub ); } 39 AUE_GETPPID STD|CAPENABLED { pid_t getppid(void); } 40 AUE_LSTAT COMPAT { int lstat( _In_z_ const char *path, _Out_ _Contains_timet_ struct ostat *ub ); } 41 AUE_DUP STD|CAPENABLED { int dup( u_int fd ); } 42 AUE_PIPE COMPAT10|CAPENABLED { int pipe(void); } 43 AUE_GETEGID STD|CAPENABLED { gid_t getegid(void); } 44 AUE_PROFILE STD|CAPENABLED { int profil( _Out_writes_bytes_(size) char *samples, size_t size, size_t offset, u_int scale ); } 45 AUE_KTRACE STD { int ktrace( _In_z_ const char *fname, int ops, int facs, int pid ); } 46 AUE_SIGACTION COMPAT|CAPENABLED { int sigaction( int signum, _In_opt_ _Contains_ptr_ struct osigaction *nsa, _Out_opt_ _Contains_ptr_ struct osigaction *osa ); } 47 AUE_GETGID STD|CAPENABLED { gid_t getgid(void); } 48 AUE_SIGPROCMASK COMPAT|CAPENABLED { int sigprocmask( int how, osigset_t mask ); } ; XXX note nonstandard (bogus) calling convention - the libc stub passes ; us the mask, not a pointer to it, and we return the old mask as the ; (int) return value. 49 AUE_GETLOGIN STD|CAPENABLED { int getlogin( _Out_writes_z_(namelen) char *namebuf, u_int namelen ); } 50 AUE_SETLOGIN STD { int setlogin( _In_z_ const char *namebuf ); } 51 AUE_ACCT STD { int acct( _In_z_ const char *path ); } 52 AUE_SIGPENDING COMPAT|CAPENABLED { int sigpending(void); } 53 AUE_SIGALTSTACK STD|CAPENABLED { int sigaltstack( _In_opt_ _Contains_long_ptr_ const struct sigaltstack *ss, _Out_opt_ _Contains_long_ptr_ struct sigaltstack *oss ); } 54 AUE_IOCTL STD|CAPENABLED { int ioctl( int fd, u_long com, _Inout_opt_ _Contains_long_ptr_ char *data ); } 55 AUE_REBOOT STD { int reboot( int opt ); } 56 AUE_REVOKE STD { int revoke( _In_z_ const char *path ); } 57 AUE_SYMLINK STD { int symlink( _In_z_ const char *path, _In_z_ const char *link ); } 58 AUE_READLINK STD { ssize_t readlink( _In_z_ const char *path, _Out_writes_z_(count) char *buf, size_t count ); } 59 AUE_EXECVE STD { int execve( _In_z_ const char *fname, _In_z_ char **argv, _In_z_ char **envv ); } 60 AUE_UMASK STD|CAPENABLED { mode_t umask( mode_t newmask ); } 61 AUE_CHROOT STD { int chroot( _In_z_ const char *path ); } 62 AUE_FSTAT COMPAT|CAPENABLED { int fstat( int fd, _Out_ _Contains_timet_ struct ostat *sb ); } 63 AUE_NULL COMPAT { int getkerninfo( int op, _Out_writes_bytes_opt(*size) char *where, _Inout_opt_ size_t *size, int arg ); } 64 AUE_NULL COMPAT|CAPENABLED { int getpagesize(void); } 65 AUE_MSYNC STD|CAPENABLED { int msync( _In_ void *addr, size_t len, int flags ); } 66 AUE_VFORK STD { int vfork(void); } 67 AUE_NULL OBSOL vread 68 AUE_NULL OBSOL vwrite 69 AUE_SBRK STD|CAPENABLED { int sbrk( int incr ); } 70 AUE_SSTK STD|CAPENABLED { int sstk( int incr ); } 71 AUE_MMAP COMPAT|CAPENABLED { void *mmap( _In_ void *addr, int len, int prot, int flags, int fd, long pos ); } 72 AUE_O_VADVISE COMPAT11 { int vadvise( int anom ); } 73 AUE_MUNMAP STD|CAPENABLED { int munmap( _In_ void *addr, size_t len ); } 74 AUE_MPROTECT STD|CAPENABLED { int mprotect( _In_ void *addr, size_t len, int prot ); } 75 AUE_MADVISE STD|CAPENABLED { int madvise( _In_ void *addr, size_t len, int behav ); } 76 AUE_NULL OBSOL vhangup 77 AUE_NULL OBSOL vlimit 78 AUE_MINCORE STD|CAPENABLED { int mincore( _In_ const void *addr, size_t len, _Out_writes_bytes_(len/PAGE_SIZE) char *vec ); } 79 AUE_GETGROUPS STD|CAPENABLED { int getgroups( int gidsetsize, _Out_writes_opt_(gidsetsize) gid_t *gidset ); } 80 AUE_SETGROUPS STD { int setgroups( int gidsetsize, _In_reads_(gidsetsize) const gid_t *gidset ); } 81 AUE_GETPGRP STD|CAPENABLED { int getpgrp(void); } 82 AUE_SETPGRP STD { int setpgid( int pid, int pgid ); } 83 AUE_SETITIMER STD|CAPENABLED { int setitimer( int which, _In_ _Contains_timet_ const struct itimerval *itv, _Out_opt_ _Contains_timet_ struct itimerval *oitv ); } 84 AUE_WAIT4 COMPAT { int wait(void); } 85 AUE_SWAPON STD { int swapon( _In_z_ const char *name ); } 86 AUE_GETITIMER STD|CAPENABLED { int getitimer( int which, _Out_ _Contains_timet_ struct itimerval *itv ); } 87 AUE_SYSCTL COMPAT|CAPENABLED { int gethostname( _Out_writes_z_(len) char *hostname, u_int len ); } 88 AUE_SYSCTL COMPAT { int sethostname( _In_reads_z_(len) char *hostname, u_int len ); } 89 AUE_GETDTABLESIZE STD|CAPENABLED { int getdtablesize(void); } 90 AUE_DUP2 STD|CAPENABLED { int dup2( u_int from, u_int to ); } 91 AUE_NULL RESERVED 92 AUE_FCNTL STD|CAPENABLED { int fcntl( int fd, int cmd, long arg ); } ; XXX should be { int fcntl(int fd, int cmd, ...); } ; but we're not ready for varargs. 93 AUE_SELECT STD|CAPENABLED { int select( int nd, _Inout_opt_ fd_set *in, _Inout_opt_ fd_set *ou, _Inout_opt_ fd_set *ex, _In_opt_ _Contains_long_timet_ struct timeval *tv ); } 94 AUE_NULL RESERVED 95 AUE_FSYNC STD|CAPENABLED { int fsync( int fd ); } 96 AUE_SETPRIORITY STD|CAPENABLED { int setpriority( int which, int who, int prio ); } 97 AUE_SOCKET STD|CAPENABLED { int socket( int domain, int type, int protocol ); } 98 AUE_CONNECT STD { int connect( int s, _In_reads_bytes_(namelen) const struct sockaddr *name, __socklen_t namelen ); } 99 AUE_ACCEPT COMPAT|CAPENABLED { int accept( int s, _Out_writes_bytes_opt_(*anamelen) struct sockaddr *name, __socklen_t *anamelen ); } 100 AUE_GETPRIORITY STD|CAPENABLED { int getpriority( int which, int who ); } 101 AUE_SEND COMPAT|CAPENABLED { int send( int s, _In_reads_bytes_(len) const void *buf, int len, int flags ); } 102 AUE_RECV COMPAT|CAPENABLED { int recv( int s, _Out_writes_bytes_(len) void *buf, int len, int flags ); } 103 AUE_SIGRETURN COMPAT|CAPENABLED { int sigreturn( _In_ struct osigcontext *sigcntxp ); } 104 AUE_BIND STD { int bind( int s, _In_reads_bytes_(namelen) const struct sockaddr *name, __socklen_t namelen ); } 105 AUE_SETSOCKOPT STD|CAPENABLED { int setsockopt( int s, int level, int name, _In_reads_bytes_opt_(valsize) const void *val, __socklen_t valsize ); } 106 AUE_LISTEN STD|CAPENABLED { int listen( int s, int backlog ); } 107 AUE_NULL OBSOL vtimes 108 AUE_NULL COMPAT|CAPENABLED { int sigvec( int signum, _In_opt_ _Contains_ptr_ struct sigvec *nsv, _Out_opt_ _Contains_ptr_ struct sigvec *osv ); } 109 AUE_NULL COMPAT|CAPENABLED { int sigblock( int mask ); } 110 AUE_NULL COMPAT|CAPENABLED { int sigsetmask( int mask ); } 111 AUE_NULL COMPAT|CAPENABLED { int sigsuspend( osigset_t mask ); } ; XXX note nonstandard (bogus) calling convention - the libc stub passes ; us the mask, not a pointer to it. 112 AUE_NULL COMPAT|CAPENABLED { int sigstack( _In_opt_ _Contains_ptr_ struct sigstack *nss, _Out_opt_ _Contains_ptr_ struct sigstack *oss ); } 113 AUE_RECVMSG COMPAT|CAPENABLED { int recvmsg( int s, _Inout_ _Contains_ptr_ struct omsghdr *msg, int flags ); } 114 AUE_SENDMSG COMPAT|CAPENABLED { int sendmsg( int s, _In_ _Contains_ptr_ const struct omsghdr *msg, int flags ); } 115 AUE_NULL OBSOL vtrace 116 AUE_GETTIMEOFDAY STD|CAPENABLED { int gettimeofday( _Out_ _Contains_long_timet_ struct timeval *tp, _Out_opt_ struct timezone *tzp ); } 117 AUE_GETRUSAGE STD|CAPENABLED { int getrusage( int who, _Out_ _Contains_long_ struct rusage *rusage ); } 118 AUE_GETSOCKOPT STD|CAPENABLED { int getsockopt( int s, int level, int name, _Out_writes_bytes_opt_(*avalsize) void *val, _Inout_ __socklen_t *avalsize ); } 119 AUE_NULL RESERVED 120 AUE_READV STD|CAPENABLED { int readv( int fd, _Inout_updates_(iovcnt) _Contains_long_ptr_ struct iovec *iovp, u_int iovcnt ); } 121 AUE_WRITEV STD|CAPENABLED { int writev( int fd, _In_reads_opt_(iovcnt) _Contains_long_ptr_ struct iovec *iovp, u_int iovcnt ); } 122 AUE_SETTIMEOFDAY STD { int settimeofday( _In_ _Contains_long_timet_ const struct timeval *tv, _In_opt_ const struct timezone *tzp ); } 123 AUE_FCHOWN STD|CAPENABLED { int fchown( int fd, int uid, int gid ); } 124 AUE_FCHMOD STD|CAPENABLED { int fchmod( int fd, mode_t mode ); } 125 AUE_RECVFROM COMPAT|CAPENABLED { int recvfrom( int s, _Out_writes_(len) void *buf, size_t len, int flags, _Out_writes_bytes_(*fromlenaddr) struct sockaddr *from, _Inout_ __socklen_t *fromlenaddr ); } 126 AUE_SETREUID STD|CAPENABLED { int setreuid( int ruid, int euid ); } 127 AUE_SETREGID STD|CAPENABLED { int setregid( int rgid, int egid ); } 128 AUE_RENAME STD { int rename( _In_z_ const char *from, _In_z_ const char *to ); } 129 AUE_TRUNCATE COMPAT { int truncate( _In_z_ const char *path, long length ); } 130 AUE_FTRUNCATE COMPAT|CAPENABLED { int ftruncate( int fd, long length ); } 131 AUE_FLOCK STD|CAPENABLED { int flock( int fd, int how ); } 132 AUE_MKFIFO STD { int mkfifo( _In_z_ const char *path, mode_t mode ); } 133 AUE_SENDTO STD|CAPENABLED { ssize_t sendto( int s, _In_reads_bytes_(len) const void *buf, size_t len, int flags, _In_reads_bytes_opt_(tolen) const struct sockaddr *to, __socklen_t tolen ); } 134 AUE_SHUTDOWN STD|CAPENABLED { int shutdown( int s, int how ); } 135 AUE_SOCKETPAIR STD|CAPENABLED { int socketpair( int domain, int type, int protocol, _Out_writes_(2) int *rsv ); } 136 AUE_MKDIR STD { int mkdir( _In_z_ const char *path, mode_t mode ); } 137 AUE_RMDIR STD { int rmdir( _In_z_ const char *path ); } 138 AUE_UTIMES STD { int utimes( _In_z_ const char *path, _In_ _Contains_long_timet_ const struct timeval *tptr ); } 139 AUE_NULL OBSOL 4.2 sigreturn 140 AUE_ADJTIME STD { int adjtime( _In_ _Contains_long_timet_ const struct timeval *delta, _Out_opt_ _Contains_long_timet_ struct timeval *olddelta ); } 141 AUE_GETPEERNAME COMPAT|CAPENABLED { int getpeername( int fdes, _Out_writes_bytes_(*alen) struct sockaddr *asa, _Inout_opt_ __socklen_t *alen ); } 142 AUE_SYSCTL COMPAT|CAPENABLED { long gethostid(void); } 143 AUE_SYSCTL COMPAT { int sethostid( long hostid ); } 144 AUE_GETRLIMIT COMPAT|CAPENABLED { int getrlimit( u_int which, _Out_ struct orlimit *rlp ); } 145 AUE_SETRLIMIT COMPAT|CAPENABLED { int setrlimit( u_int which, _Out_ struct orlimit *rlp ); } 146 AUE_KILLPG COMPAT { int killpg( int pgid, int signum ); } 147 AUE_SETSID STD|CAPENABLED { int setsid(void); } 148 AUE_QUOTACTL STD { int quotactl( _In_z_ const char *path, int cmd, int uid, _In_ void *arg ); } 149 AUE_O_QUOTA COMPAT { int quota(void); } 150 AUE_GETSOCKNAME COMPAT|CAPENABLED { int getsockname( int fdes, _Out_writes_bytes_(*alen) struct sockaddr *asa, _Inout_ __socklen_t *alen ); } 151-153 AUE_NULL RESERVED ; 154 is initialised by the NLM code, if present. 154 AUE_NULL NOSTD { int nlm_syscall( int debug_level, int grace_period, int addr_count, _In_reads_(addr_count) char **addrs ); } ; 155 is initialized by the NFS code, if present. 155 AUE_NFS_SVC NOSTD { int nfssvc( int flag, _In_ void *argp ); } 156 AUE_GETDIRENTRIES COMPAT|CAPENABLED { int getdirentries( int fd, _Out_writes_bytes_(count) char *buf, u_int count, _Out_ long *basep ); } 157 AUE_STATFS COMPAT4 { int statfs( _In_z_ const char *path, _Out_ _Contains_long_ struct ostatfs *buf ); } 158 AUE_FSTATFS COMPAT4|CAPENABLED { int fstatfs( int fd, _Out_ _Contains_long_ struct ostatfs *buf ); } 159 AUE_NULL RESERVED 160 AUE_LGETFH STD { int lgetfh( _In_z_ const char *fname, _Out_ struct fhandle *fhp ); } 161 AUE_NFS_GETFH STD { int getfh( _In_z_ const char *fname, _Out_ struct fhandle *fhp ); } 162 AUE_SYSCTL COMPAT4|CAPENABLED { int getdomainname( _Out_writes_z_(len) char *domainname, int len ); } 163 AUE_SYSCTL COMPAT4 { int setdomainname( _In_reads_z_(len) char *domainname, int len ); } 164 AUE_NULL COMPAT4 { int uname( _Out_ struct utsname *name ); } 165 AUE_SYSARCH STD|CAPENABLED { int sysarch( int op, _In_z_ char *parms ); } 166 AUE_RTPRIO STD|CAPENABLED { int rtprio( int function, pid_t pid, _Inout_ struct rtprio *rtp ); } 167-168 AUE_NULL RESERVED 169 AUE_SEMSYS NOSTD { int semsys( int which, int a2, int a3, int a4, int a5 ); } ; XXX should be { int semsys(int which, ...); } 170 AUE_MSGSYS NOSTD { int msgsys( int which, int a2, int a3, int a4, int a5, int a6 ); } ; XXX should be { int msgsys(int which, ...); } 171 AUE_SHMSYS NOSTD { int shmsys( int which, int a2, int a3, int a4 ); } ; XXX should be { int shmsys(int which, ...); } 172 AUE_NULL RESERVED 173 AUE_PREAD COMPAT6|CAPENABLED { ssize_t pread( int fd, _Out_writes_bytes_(nbyte) void *buf, size_t nbyte, int pad, off_t offset ); } 174 AUE_PWRITE COMPAT6|CAPENABLED { ssize_t pwrite( int fd, _In_reads_bytes_(nbyte) const void *buf, size_t nbyte, int pad, off_t offset ); } 175 AUE_SETFIB STD { int setfib( int fibnum ); } 176 AUE_NTP_ADJTIME STD { int ntp_adjtime( _Inout_ _Contains_long_ struct timex *tp ); } 177-180 AUE_NULL RESERVED 181 AUE_SETGID STD|CAPENABLED { int setgid( gid_t gid ); } 182 AUE_SETEGID STD|CAPENABLED { int setegid( gid_t egid ); } 183 AUE_SETEUID STD|CAPENABLED { int seteuid( uid_t euid ); } 184 AUE_NULL OBSOL lfs_bmapv 185 AUE_NULL OBSOL lfs_markv 186 AUE_NULL OBSOL lfs_segclean 187 AUE_NULL OBSOL lfs_segwait 188 AUE_STAT COMPAT11 { int stat( _In_z_ const char *path, _Out_ _Contains_timet_ struct freebsd11_stat *ub ); } 189 AUE_FSTAT COMPAT11|CAPENABLED { int fstat( int fd, _Out_ _Contains_timet_ struct freebsd11_stat *sb ); } 190 AUE_LSTAT COMPAT11 { int lstat( _In_z_ const char *path, _Out_ _Contains_timet_ struct freebsd11_stat *ub ); } 191 AUE_PATHCONF STD { int pathconf( _In_z_ const char *path, int name ); } 192 AUE_FPATHCONF STD|CAPENABLED { int fpathconf( int fd, int name ); } 193 AUE_NULL RESERVED 194 AUE_GETRLIMIT STD|CAPENABLED { int getrlimit( u_int which, _Out_ struct rlimit *rlp ); } 195 AUE_SETRLIMIT STD|CAPENABLED { int setrlimit( u_int which, _In_ struct rlimit *rlp ); } 196 AUE_GETDIRENTRIES COMPAT11|CAPENABLED { int getdirentries( int fd, _Out_writes_bytes_(count) char *buf, u_int count, _Out_ long *basep ); } 197 AUE_MMAP COMPAT6|CAPENABLED { void *mmap( _In_ void *addr, size_t len, int prot, int flags, int fd, int pad, off_t pos ); } 198 AUE_NULL SYSMUX { int __syscall( int64_t number, ... ); } 199 AUE_LSEEK COMPAT6|CAPENABLED { off_t lseek( int fd, int pad, off_t offset, int whence ); } 200 AUE_TRUNCATE COMPAT6 { int truncate( _In_z_ const char *path, int pad, off_t length ); } 201 AUE_FTRUNCATE COMPAT6|CAPENABLED { int ftruncate( int fd, int pad, off_t length ); } 202 AUE_SYSCTL STD|CAPENABLED { int __sysctl( _In_reads_(namelen) int *name, u_int namelen, _Out_writes_bytes_opt_(*oldlenp) void *old, _Inout_opt_ size_t *oldlenp, _In_reads_bytes_opt_(newlen) const void *new, size_t newlen ); } 203 AUE_MLOCK STD|CAPENABLED { int mlock( _In_ const void *addr, size_t len ); } 204 AUE_MUNLOCK STD|CAPENABLED { int munlock( _In_ const void *addr, size_t len ); } 205 AUE_UNDELETE STD { int undelete( _In_z_ const char *path ); } 206 AUE_FUTIMES STD|CAPENABLED { int futimes( int fd, _In_reads_(2) _Contains_long_timet_ const struct timeval *tptr ); } 207 AUE_GETPGID STD|CAPENABLED { int getpgid( pid_t pid ); } 208 AUE_NULL RESERVED 209 AUE_POLL STD|CAPENABLED { int poll( _Inout_updates_(nfds) struct pollfd *fds, u_int nfds, int timeout ); } ; ; The following are reserved for loadable syscalls ; 210 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 211 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 212 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 213 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 214 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 215 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 216 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 217 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 218 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 219 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int 220 AUE_SEMCTL COMPAT7|NOSTD { int __semctl( int semid, int semnum, int cmd, _Contains_ptr_ union semun_old *arg ); } 221 AUE_SEMGET NOSTD { int semget( key_t key, int nsems, int semflg ); } 222 AUE_SEMOP NOSTD { int semop( int semid, _In_reads_(nsops) struct sembuf *sops, size_t nsops ); } 223 AUE_NULL OBSOL semconfig 224 AUE_MSGCTL COMPAT7|NOSTD { int msgctl( int msqid, int cmd, _Contains_long_ptr_timet_ struct msqid_ds_old *buf ); } 225 AUE_MSGGET NOSTD { int msgget( key_t key, int msgflg ); } 226 AUE_MSGSND NOSTD { int msgsnd( int msqid, _In_reads_bytes_(msgsz) _Contains_long_ const void *msgp, size_t msgsz, int msgflg ); } 227 AUE_MSGRCV NOSTD { ssize_t msgrcv( int msqid, _Out_writes_bytes_(msgsz) _Contains_long_ void *msgp, size_t msgsz, long msgtyp, int msgflg ); } 228 AUE_SHMAT NOSTD { void *shmat( int shmid, _In_ const void *shmaddr, int shmflg ); } 229 AUE_SHMCTL COMPAT7|NOSTD { int shmctl( int shmid, int cmd, _Inout_opt_ _Contains_long_ struct shmid_ds_old *buf ); } 230 AUE_SHMDT NOSTD { int shmdt( _In_ const void *shmaddr ); } 231 AUE_SHMGET NOSTD { int shmget( key_t key, size_t size, int shmflg ); } 232 AUE_NULL STD|CAPENABLED { int clock_gettime( clockid_t clock_id, _Out_ _Contains_long_timet_ struct timespec *tp ); } 233 AUE_CLOCK_SETTIME STD { int clock_settime( clockid_t clock_id, _In_ _Contains_long_timet_ const struct timespec *tp ); } 234 AUE_NULL STD|CAPENABLED { int clock_getres( clockid_t clock_id, _Out_ _Contains_long_timet_ struct timespec *tp ); } 235 AUE_NULL STD|CAPENABLED { int ktimer_create( clockid_t clock_id, _In_ _Contains_long_ptr_ struct sigevent *evp, _Out_ int *timerid ); } 236 AUE_NULL STD|CAPENABLED { int ktimer_delete( int timerid ); } 237 AUE_NULL STD|CAPENABLED { int ktimer_settime( int timerid, int flags, _In_ _Contains_long_timet_ const struct itimerspec *value, _Out_opt_ _Contains_long_timet_ struct itimerspec *ovalue ); } 238 AUE_NULL STD|CAPENABLED { int ktimer_gettime( int timerid, _Out_ _Contains_long_timet_ struct itimerspec *value ); } 239 AUE_NULL STD|CAPENABLED { int ktimer_getoverrun( int timerid ); } 240 AUE_NULL STD|CAPENABLED { int nanosleep( _In_ _Contains_long_timet_ const struct timespec *rqtp, _Out_opt_ _Contains_long_timet_ struct timespec *rmtp ); } 241 AUE_NULL STD { int ffclock_getcounter( _Out_ ffcounter *ffcount ); } 242 AUE_NULL STD { int ffclock_setestimate( _In_ _Contains_timet_ struct ffclock_estimate *cest ); } 243 AUE_NULL STD { int ffclock_getestimate( _Out_ _Contains_timet_ struct ffclock_estimate *cest ); } 244 AUE_NULL STD { int clock_nanosleep( clockid_t clock_id, int flags, _In_ _Contains_long_timet_ const struct timespec *rqtp, _Out_opt_ _Contains_long_timet_ struct timespec *rmtp ); } 245-246 AUE_NULL RESERVED 247 AUE_NULL STD { int clock_getcpuclockid2( id_t id, int which, _Out_ clockid_t *clock_id ); } 248 AUE_NULL STD|CAPENABLED { int ntp_gettime( _Out_ _Contains_long_timet_ struct ntptimeval *ntvp ); } 249 AUE_NULL RESERVED 250 AUE_MINHERIT STD|CAPENABLED { int minherit( _In_ void *addr, size_t len, int inherit ); } 251 AUE_RFORK STD { int rfork( int flags ); } 252 AUE_POLL OBSOL openbsd_poll 253 AUE_ISSETUGID STD|CAPENABLED { int issetugid(void); } 254 AUE_LCHOWN STD { int lchown( _In_z_ const char *path, int uid, int gid ); } 255 AUE_AIO_READ STD|CAPENABLED { int aio_read( _Inout_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 256 AUE_AIO_WRITE STD|CAPENABLED { int aio_write( _Inout_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 257 AUE_LIO_LISTIO STD|CAPENABLED { int lio_listio( int mode, _Inout_updates_(nent) _Contains_long_ptr_ struct aiocb * const *acb_list, int nent, _In_opt_ _Contains_long_ptr_ struct sigevent *sig ); } 258-271 AUE_NULL RESERVED 272 AUE_O_GETDENTS COMPAT11|CAPENABLED { int getdents( int fd, _Out_writes_bytes_(count) char *buf, size_t count ); } 273 AUE_NULL RESERVED 274 AUE_LCHMOD STD { int lchmod( _In_z_ const char *path, mode_t mode ); } 275 AUE_NULL OBSOL netbsd_lchown 276 AUE_LUTIMES STD { int lutimes( _In_z_ const char *path, _In_ _Contains_long_timet_ const struct timeval *tptr ); } 277 AUE_NULL OBSOL netbsd_msync 278 AUE_STAT COMPAT11 { int nstat( _In_z_ const char *path, _Out_ _Contains_long_timet_ struct nstat *ub ); } 279 AUE_FSTAT COMPAT11 { int nfstat( int fd, _Out_ _Contains_long_timet_ struct nstat *sb ); } 280 AUE_LSTAT COMPAT11 { int nlstat( _In_z_ const char *path, _Out_ _Contains_long_timet_ struct nstat *ub ); } 281-288 AUE_NULL RESERVED 289 AUE_PREADV STD|CAPENABLED { ssize_t preadv( int fd, _In_reads_(iovcnt) _Contains_long_ptr_ struct iovec *iovp, u_int iovcnt, off_t offset ); } 290 AUE_PWRITEV STD|CAPENABLED { ssize_t pwritev( int fd, _In_reads_(iovcnt) _Contains_long_ptr_ struct iovec *iovp, u_int iovcnt, off_t offset ); } 291-296 AUE_NULL RESERVED 297 AUE_FHSTATFS COMPAT4 { int fhstatfs( _In_ const struct fhandle *u_fhp, _Out_ _Contains_long_ struct ostatfs *buf ); } 298 AUE_FHOPEN STD { int fhopen( _In_ const struct fhandle *u_fhp, int flags ); } 299 AUE_FHSTAT COMPAT11 { int fhstat( _In_ const struct fhandle *u_fhp, _Out_ _Contains_long_timet_ struct freebsd11_stat *sb ); } 300 AUE_NULL STD { int modnext( int modid ); } 301 AUE_NULL STD { int modstat( int modid, _Out_ _Contains_long_ struct module_stat *stat ); } 302 AUE_NULL STD { int modfnext( int modid ); } 303 AUE_NULL STD { int modfind( _In_z_ const char *name ); } 304 AUE_MODLOAD STD { int kldload( _In_z_ const char *file ); } 305 AUE_MODUNLOAD STD { int kldunload( int fileid ); } 306 AUE_NULL STD { int kldfind( _In_z_ const char *file ); } 307 AUE_NULL STD { int kldnext( int fileid ); } 308 AUE_NULL STD { int kldstat( int fileid, _Out_ _Contains_long_ptr_ struct kld_file_stat *stat ); } 309 AUE_NULL STD { int kldfirstmod( int fileid ); } 310 AUE_GETSID STD|CAPENABLED { int getsid( pid_t pid ); } 311 AUE_SETRESUID STD|CAPENABLED { int setresuid( uid_t ruid, uid_t euid, uid_t suid ); } 312 AUE_SETRESGID STD|CAPENABLED { int setresgid( gid_t rgid, gid_t egid, gid_t sgid ); } 313 AUE_NULL OBSOL signanosleep 314 AUE_AIO_RETURN STD|CAPENABLED { ssize_t aio_return( _Inout_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 315 AUE_AIO_SUSPEND STD|CAPENABLED { int aio_suspend( _Inout_updates_(nent) _Contains_long_ptr_ struct aiocb * const * aiocbp, int nent, _In_opt_ _Contains_long_timet_ const struct timespec *timeout ); } 316 AUE_AIO_CANCEL STD|CAPENABLED { int aio_cancel( int fd, _In_opt_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 317 AUE_AIO_ERROR STD|CAPENABLED { int aio_error( _In_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 318 AUE_AIO_READ COMPAT6|CAPENABLED { int aio_read( _Inout_ _Contains_long_ptr_ struct oaiocb *aiocbp ); } 319 AUE_AIO_WRITE COMPAT6|CAPENABLED { int aio_write( _Inout_ _Contains_long_ptr_ struct oaiocb *aiocbp ); } 320 AUE_LIO_LISTIO COMPAT6|CAPENABLED { int lio_listio( int mode, _Inout_updates_(nent) _Contains_long_ptr_ struct oaiocb * const *acb_list, int nent, _In_opt_ _Contains_ptr_ struct osigevent *sig ); } 321 AUE_NULL STD|CAPENABLED { int yield(void); } 322 AUE_NULL OBSOL thr_sleep 323 AUE_NULL OBSOL thr_wakeup 324 AUE_MLOCKALL STD|CAPENABLED { int mlockall( int how ); } 325 AUE_MUNLOCKALL STD|CAPENABLED { int munlockall(void); } 326 AUE_GETCWD STD { int __getcwd( _Out_writes_z_(buflen) char *buf, size_t buflen ); } 327 AUE_NULL STD|CAPENABLED { int sched_setparam( pid_t pid, _In_ const struct sched_param *param ); } 328 AUE_NULL STD|CAPENABLED { int sched_getparam( pid_t pid, _Out_ struct sched_param *param ); } 329 AUE_NULL STD|CAPENABLED { int sched_setscheduler( pid_t pid, int policy, _In_ const struct sched_param *param ); } 330 AUE_NULL STD|CAPENABLED { int sched_getscheduler( pid_t pid ); } 331 AUE_NULL STD|CAPENABLED { int sched_yield(void); } 332 AUE_NULL STD|CAPENABLED { int sched_get_priority_max( int policy ); } 333 AUE_NULL STD|CAPENABLED { int sched_get_priority_min( int policy ); } 334 AUE_NULL STD|CAPENABLED { int sched_rr_get_interval( pid_t pid, _Out_ _Contains_long_timet_ struct timespec *interval ); } 335 AUE_NULL STD|CAPENABLED { int utrace( _In_reads_bytes_(len) const void *addr, size_t len ); } 336 AUE_SENDFILE COMPAT4|CAPENABLED { int sendfile( int fd, int s, off_t offset, size_t nbytes, _In_opt_ _Contains_ptr_ struct sf_hdtr *hdtr, _Out_opt_ off_t *sbytes, int flags ); } 337 AUE_NULL STD { int kldsym( int fileid, int cmd, _In_ _Contains_long_ptr_ void *data ); } 338 AUE_JAIL STD { int jail( _In_ _Contains_ptr_ struct jail *jail ); } 339 AUE_NULL NOSTD|NOTSTATIC { int nnpfs_syscall( int operation, char *a_pathP, int a_opcode, void *a_paramsP, int a_followSymlinks ); } 340 AUE_SIGPROCMASK STD|CAPENABLED { int sigprocmask( int how, _In_opt_ const sigset_t *set, _Out_opt_ sigset_t *oset ); } 341 AUE_SIGSUSPEND STD|CAPENABLED { int sigsuspend( _In_ const sigset_t *sigmask ); } 342 AUE_SIGACTION COMPAT4|CAPENABLED { int sigaction( int sig, _In_opt_ _Contains_ptr_ const struct sigaction *act, _Out_opt_ _Contains_ptr_ struct sigaction *oact ); } 343 AUE_SIGPENDING STD|CAPENABLED { int sigpending( _In_ sigset_t *set ); } 344 AUE_SIGRETURN COMPAT4|CAPENABLED { int sigreturn( _In_ _Contains_long_ptr_ const struct freebsd4_ucontext *sigcntxp ); } 345 AUE_SIGWAIT STD|CAPENABLED { int sigtimedwait( _In_ const sigset_t *set, _Out_opt_ _Contains_long_ptr_ struct siginfo *info, _In_opt_ _Contains_long_timet_ const struct timespec *timeout ); } 346 AUE_NULL STD|CAPENABLED { int sigwaitinfo( _In_ const sigset_t *set, _Out_opt_ _Contains_long_ptr_ struct siginfo *info ); } 347 AUE_ACL_GET_FILE STD { int __acl_get_file( _In_z_ const char *path, acl_type_t type, _Out_ struct acl *aclp ); } 348 AUE_ACL_SET_FILE STD { int __acl_set_file( _In_z_ const char *path, acl_type_t type, _In_ struct acl *aclp ); } 349 AUE_ACL_GET_FD STD|CAPENABLED { int __acl_get_fd( int filedes, acl_type_t type, _Out_ struct acl *aclp ); } 350 AUE_ACL_SET_FD STD|CAPENABLED { int __acl_set_fd( int filedes, acl_type_t type, _In_ struct acl *aclp ); } 351 AUE_ACL_DELETE_FILE STD { int __acl_delete_file( _In_z_ const char *path, acl_type_t type ); } 352 AUE_ACL_DELETE_FD STD|CAPENABLED { int __acl_delete_fd( int filedes, acl_type_t type ); } 353 AUE_ACL_CHECK_FILE STD { int __acl_aclcheck_file( _In_z_ const char *path, acl_type_t type, _In_ struct acl *aclp ); } 354 AUE_ACL_CHECK_FD STD|CAPENABLED { int __acl_aclcheck_fd( int filedes, acl_type_t type, _In_ struct acl *aclp ); } 355 AUE_EXTATTRCTL STD { int extattrctl( _In_z_ const char *path, int cmd, _In_z_opt_ const char *filename, int attrnamespace, _In_z_ const char *attrname ); } 356 AUE_EXTATTR_SET_FILE STD { ssize_t extattr_set_file( _In_z_ const char *path, int attrnamespace, _In_z_ const char *attrname, _In_reads_bytes_(nbytes) void *data, size_t nbytes ); } 357 AUE_EXTATTR_GET_FILE STD { ssize_t extattr_get_file( _In_z_ const char *path, int attrnamespace, _In_z_ const char *attrname, _Out_writes_bytes_(nbytes) void *data, size_t nbytes ); } 358 AUE_EXTATTR_DELETE_FILE STD { int extattr_delete_file( _In_z_ const char *path, int attrnamespace, _In_z_ const char *attrname ); } 359 AUE_AIO_WAITCOMPLETE STD|CAPENABLED { ssize_t aio_waitcomplete( _Outptr_result_maybenull_ struct aiocb **aiocbp, _In_opt_ _Contains_long_timet_ struct timespec *timeout ); } 360 AUE_GETRESUID STD|CAPENABLED { int getresuid( _Out_opt_ uid_t *ruid, _Out_opt_ uid_t *euid, _Out_opt_ uid_t *suid ); } 361 AUE_GETRESGID STD|CAPENABLED { int getresgid( _Out_opt_ gid_t *rgid, _Out_opt_ gid_t *egid, _Out_opt_ gid_t *sgid ); } 362 AUE_KQUEUE STD|CAPENABLED { int kqueue(void); } 363 AUE_KEVENT COMPAT11|CAPENABLED { int kevent( int fd, _In_reads_opt_(nchanges) _Contains_ptr_ const struct freebsd11_kevent *changelist, int nchanges, _Out_writes_opt_(nevents) _Contains_ptr_ struct freebsd11_kevent *eventlist, int nevents, _In_opt_ _Contains_long_timet_ const struct timespec *timeout ); } 364 AUE_NULL OBSOL __cap_get_proc 365 AUE_NULL OBSOL __cap_set_proc 366 AUE_NULL OBSOL __cap_get_fd 367 AUE_NULL OBSOL __cap_get_file 368 AUE_NULL OBSOL __cap_set_fd 369 AUE_NULL OBSOL __cap_set_file 370 AUE_NULL RESERVED 371 AUE_EXTATTR_SET_FD STD|CAPENABLED { ssize_t extattr_set_fd( int fd, int attrnamespace, _In_z_ const char *attrname, _In_reads_bytes_(nbytes) void *data, size_t nbytes ); } 372 AUE_EXTATTR_GET_FD STD|CAPENABLED { ssize_t extattr_get_fd( int fd, int attrnamespace, _In_z_ const char *attrname, _Out_writes_bytes_(nbytes) void *data, size_t nbytes ); } 373 AUE_EXTATTR_DELETE_FD STD|CAPENABLED { int extattr_delete_fd( int fd, int attrnamespace, _In_z_ const char *attrname ); } 374 AUE_SETUGID STD { int __setugid( int flag ); } 375 AUE_NULL OBSOL nfsclnt 376 AUE_EACCESS STD { int eaccess( _In_z_ const char *path, int amode ); } 377 AUE_NULL NOSTD|NOTSTATIC { int afs3_syscall( long syscall, long parm1, long parm2, long parm3, long parm4, long parm5, long parm6 ); } 378 AUE_NMOUNT STD { int nmount( _In_reads_(iovcnt) _Contains_long_ptr_ struct iovec *iovp, unsigned int iovcnt, int flags ); } 379 AUE_NULL OBSOL kse_exit 380 AUE_NULL OBSOL kse_wakeup 381 AUE_NULL OBSOL kse_create 382 AUE_NULL OBSOL kse_thr_interrupt 383 AUE_NULL OBSOL kse_release 384 AUE_NULL STD|CAPENABLED { int __mac_get_proc( _In_ _Contains_long_ptr_ struct mac *mac_p ); } 385 AUE_NULL STD|CAPENABLED { int __mac_set_proc( _In_ _Contains_long_ptr_ struct mac *mac_p ); } 386 AUE_NULL STD|CAPENABLED { int __mac_get_fd( int fd, _In_ _Contains_long_ptr_ struct mac *mac_p ); } 387 AUE_NULL STD { int __mac_get_file( _In_z_ const char *path_p, _In_ _Contains_long_ptr_ struct mac *mac_p ); } 388 AUE_NULL STD|CAPENABLED { int __mac_set_fd( int fd, _In_ _Contains_long_ptr_ struct mac *mac_p ); } 389 AUE_NULL STD { int __mac_set_file( _In_z_ const char *path_p, _In_ _Contains_long_ptr_ struct mac *mac_p ); } 390 AUE_NULL STD { int kenv( int what, _In_z_opt_ const char *name, _Inout_updates_opt_(len) char *value, int len ); } 391 AUE_LCHFLAGS STD { int lchflags( _In_z_ const char *path, u_long flags ); } 392 AUE_NULL STD|CAPENABLED { int uuidgen( _Out_writes_(count) struct uuid *store, int count ); } 393 AUE_SENDFILE STD|CAPENABLED { int sendfile( int fd, int s, off_t offset, size_t nbytes, _In_opt_ _Contains_ptr_ struct sf_hdtr *hdtr, _Out_opt_ off_t *sbytes, int flags ); } 394 AUE_NULL STD { int mac_syscall( _In_z_ const char *policy, int call, _In_opt_ void *arg ); } 395 AUE_GETFSSTAT COMPAT11 { int getfsstat( _Out_writes_bytes_opt_(bufsize) struct freebsd11_statfs *buf, long bufsize, int mode ); } 396 AUE_STATFS COMPAT11 { int statfs( _In_z_ const char *path, _Out_ struct freebsd11_statfs *buf ); } 397 AUE_FSTATFS COMPAT11|CAPENABLED { int fstatfs( int fd, _Out_ struct freebsd11_statfs *buf ); } 398 AUE_FHSTATFS COMPAT11 { int fhstatfs( _In_ const struct fhandle *u_fhp, _Out_ struct freebsd11_statfs *buf ); } 399 AUE_NULL RESERVED 400 AUE_SEMCLOSE NOSTD { int ksem_close( semid_t id ); } 401 AUE_SEMPOST NOSTD { int ksem_post( semid_t id ); } 402 AUE_SEMWAIT NOSTD { int ksem_wait( semid_t id ); } 403 AUE_SEMTRYWAIT NOSTD { int ksem_trywait( semid_t id ); } 404 AUE_SEMINIT NOSTD { int ksem_init( _Out_ semid_t *idp, unsigned int value ); } 405 AUE_SEMOPEN NOSTD { int ksem_open( _Out_ semid_t *idp, _In_z_ const char *name, int oflag, mode_t mode, unsigned int value ); } 406 AUE_SEMUNLINK NOSTD { int ksem_unlink( _In_z_ const char *name ); } 407 AUE_SEMGETVALUE NOSTD { int ksem_getvalue( semid_t id, _Out_ int *val ); } 408 AUE_SEMDESTROY NOSTD { int ksem_destroy( semid_t id ); } 409 AUE_NULL STD { int __mac_get_pid( pid_t pid, _In_ _Contains_long_ptr_ struct mac *mac_p ); } 410 AUE_NULL STD { int __mac_get_link( _In_z_ const char *path_p, _In_ _Contains_long_ptr_ struct mac *mac_p ); } 411 AUE_NULL STD { int __mac_set_link( _In_z_ const char *path_p, _In_ _Contains_long_ptr_ struct mac *mac_p ); } 412 AUE_EXTATTR_SET_LINK STD { ssize_t extattr_set_link( _In_z_ const char *path, int attrnamespace, _In_z_ const char *attrname, _In_reads_bytes_(nbytes) void *data, size_t nbytes ); } 413 AUE_EXTATTR_GET_LINK STD { ssize_t extattr_get_link( _In_z_ const char *path, int attrnamespace, _In_z_ const char *attrname, _Out_writes_bytes_(nbytes) void *data, size_t nbytes ); } 414 AUE_EXTATTR_DELETE_LINK STD { int extattr_delete_link( _In_z_ const char *path, int attrnamespace, _In_z_ const char *attrname ); } 415 AUE_NULL STD { int __mac_execve( _In_z_ const char *fname, _In_ char **argv, _In_ char **envv, _In_ _Contains_long_ptr_ struct mac *mac_p ); } 416 AUE_SIGACTION STD|CAPENABLED { int sigaction( int sig, _In_opt_ _Contains_ptr_ const struct sigaction *act, _Out_opt_ _Contains_ptr_ struct sigaction *oact ); } 417 AUE_SIGRETURN STD|CAPENABLED { int sigreturn( _In_ _Contains_long_ptr_ const struct __ucontext *sigcntxp ); } 418-420 AUE_NULL RESERVED 421 AUE_NULL STD|CAPENABLED { int getcontext( _Out_ _Contains_long_ptr_ struct __ucontext *ucp ); } 422 AUE_NULL STD|CAPENABLED { int setcontext( _In_ _Contains_long_ptr_ const struct __ucontext *ucp ); } 423 AUE_NULL STD { int swapcontext( _Out_ _Contains_long_ptr_ struct __ucontext *oucp, _In_ _Contains_long_ptr_ const struct __ucontext *ucp ); } 424 AUE_SWAPOFF COMPAT13 { int swapoff( _In_z_ const char *name ); } 425 AUE_ACL_GET_LINK STD { int __acl_get_link( _In_z_ const char *path, acl_type_t type, _Out_ struct acl *aclp ); } 426 AUE_ACL_SET_LINK STD { int __acl_set_link( _In_z_ const char *path, acl_type_t type, _In_ struct acl *aclp ); } 427 AUE_ACL_DELETE_LINK STD { int __acl_delete_link( _In_z_ const char *path, acl_type_t type ); } 428 AUE_ACL_CHECK_LINK STD { int __acl_aclcheck_link( _In_z_ const char *path, acl_type_t type, _In_ struct acl *aclp ); } 429 AUE_SIGWAIT STD|CAPENABLED { int sigwait( _In_ const sigset_t *set, _Out_ int *sig ); } 430 AUE_THR_CREATE STD|CAPENABLED { int thr_create( _In_ _Contains_long_ptr_ ucontext_t *ctx, _Out_ long *id, int flags ); } 431 AUE_THR_EXIT STD|CAPENABLED { void thr_exit( _Out_opt_ long *state ); } 432 AUE_NULL STD|CAPENABLED { int thr_self( _Out_ long *id ); } 433 AUE_THR_KILL STD|CAPENABLED { int thr_kill( long id, int sig ); } 434 AUE_NULL COMPAT10 { int _umtx_lock( _Inout_ struct umtx *umtx ); } 435 AUE_NULL COMPAT10 { int _umtx_unlock( _Inout_ struct umtx *umtx ); } 436 AUE_JAIL_ATTACH STD { int jail_attach( int jid ); } 437 AUE_EXTATTR_LIST_FD STD|CAPENABLED { ssize_t extattr_list_fd( int fd, int attrnamespace, _Out_writes_bytes_opt_(nbytes) void *data, size_t nbytes ); } 438 AUE_EXTATTR_LIST_FILE STD { ssize_t extattr_list_file( _In_z_ const char *path, int attrnamespace, _Out_writes_bytes_opt_(nbytes) void *data, size_t nbytes ); } 439 AUE_EXTATTR_LIST_LINK STD { ssize_t extattr_list_link( _In_z_ const char *path, int attrnamespace, _Out_writes_bytes_opt_(nbytes) void *data, size_t nbytes ); } 440 AUE_NULL OBSOL kse_switchin 441 AUE_SEMWAIT NOSTD { int ksem_timedwait( semid_t id, _In_opt_ _Contains_long_timet_ const struct timespec *abstime ); } 442 AUE_NULL STD|CAPENABLED { int thr_suspend( _In_opt_ _Contains_long_timet_ const struct timespec *timeout ); } 443 AUE_NULL STD|CAPENABLED { int thr_wake( long id ); } 444 AUE_MODUNLOAD STD { int kldunloadf( int fileid, int flags ); } 445 AUE_AUDIT STD { int audit( _In_reads_bytes_(length) const void *record, u_int length ); } 446 AUE_AUDITON STD { int auditon( int cmd, _In_opt_ void *data, u_int length ); } 447 AUE_GETAUID STD|CAPENABLED { int getauid( _Out_ uid_t *auid ); } 448 AUE_SETAUID STD|CAPENABLED { int setauid( _In_ uid_t *auid ); } 449 AUE_GETAUDIT STD|CAPENABLED { int getaudit( _Out_ struct auditinfo *auditinfo ); } 450 AUE_SETAUDIT STD|CAPENABLED { int setaudit( _In_ struct auditinfo *auditinfo ); } 451 AUE_GETAUDIT_ADDR STD|CAPENABLED { int getaudit_addr( _Out_writes_bytes_(length) struct auditinfo_addr *auditinfo_addr, u_int length ); } 452 AUE_SETAUDIT_ADDR STD|CAPENABLED { int setaudit_addr( _In_reads_bytes_(length) struct auditinfo_addr *auditinfo_addr, u_int length ); } 453 AUE_AUDITCTL STD { int auditctl( _In_z_ const char *path ); } 454 AUE_NULL STD|CAPENABLED { int _umtx_op( _Inout_ void *obj, int op, u_long val, _In_ void *uaddr1, _In_ void *uaddr2 ); } 455 AUE_THR_NEW STD|CAPENABLED { int thr_new( _In_ _Contains_long_ptr_ struct thr_param *param, int param_size ); } 456 AUE_NULL STD|CAPENABLED { int sigqueue( pid_t pid, int signum, _In_ void *value ); } 457 AUE_MQ_OPEN NOSTD { int kmq_open( _In_z_ const char *path, int flags, mode_t mode, _In_opt_ _Contains_long_ const struct mq_attr *attr ); } 458 AUE_MQ_SETATTR NOSTD|CAPENABLED { int kmq_setattr( int mqd, _In_opt_ _Contains_long_ const struct mq_attr *attr, _Out_opt_ _Contains_long_ struct mq_attr *oattr ); } 459 AUE_MQ_TIMEDRECEIVE NOSTD|CAPENABLED { int kmq_timedreceive( int mqd, _Out_writes_bytes_(msg_len) char *msg_ptr, size_t msg_len, _Out_opt_ unsigned *msg_prio, _In_opt_ _Contains_long_timet_ const struct timespec *abs_timeout ); } 460 AUE_MQ_TIMEDSEND NOSTD|CAPENABLED { int kmq_timedsend( int mqd, _In_reads_bytes_(msg_len) const char *msg_ptr, size_t msg_len, unsigned msg_prio, _In_opt_ _Contains_long_timet_ const struct timespec *abs_timeout ); } 461 AUE_MQ_NOTIFY NOSTD|CAPENABLED { int kmq_notify( int mqd, _In_opt_ _Contains_long_ptr_ const struct sigevent *sigev ); } 462 AUE_MQ_UNLINK NOSTD { int kmq_unlink( _In_z_ const char *path ); } 463 AUE_NULL STD|CAPENABLED { void abort2( _In_z_ const char *why, int nargs, _In_reads_(nargs) void **args ); } 464 AUE_NULL STD|CAPENABLED { int thr_set_name( long id, _In_z_ const char *name ); } 465 AUE_AIO_FSYNC STD|CAPENABLED { int aio_fsync( int op, _In_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 466 AUE_RTPRIO STD|CAPENABLED { int rtprio_thread( int function, lwpid_t lwpid, _Inout_ struct rtprio *rtp ); } 467-470 AUE_NULL RESERVED 471 AUE_SCTP_PEELOFF NOSTD|CAPENABLED { int sctp_peeloff( int sd, uint32_t name ); } 472 AUE_SCTP_GENERIC_SENDMSG NOSTD|CAPENABLED { int sctp_generic_sendmsg( int sd, _In_reads_bytes_(mlen) void *msg, int mlen, _In_reads_bytes_(tolen) const struct sockaddr *to, __socklen_t tolen, _In_opt_ struct sctp_sndrcvinfo *sinfo, int flags ); } 473 AUE_SCTP_GENERIC_SENDMSG_IOV NOSTD|CAPENABLED { int sctp_generic_sendmsg_iov( int sd, _In_reads_(iovlen) _Contains_long_ptr_ struct iovec *iov, int iovlen, _In_reads_bytes_(tolen) const struct sockaddr *to, __socklen_t tolen, _In_opt_ struct sctp_sndrcvinfo *sinfo, int flags ); } 474 AUE_SCTP_GENERIC_RECVMSG NOSTD|CAPENABLED { int sctp_generic_recvmsg( int sd, _In_reads_(iovlen) _Contains_long_ptr_ struct iovec *iov, int iovlen, _Out_writes_bytes_(*fromlenaddr) struct sockaddr *from, _Out_ __socklen_t *fromlenaddr, _In_opt_ struct sctp_sndrcvinfo *sinfo, _Out_opt_ int *msg_flags ); } 475 AUE_PREAD STD|CAPENABLED { ssize_t pread( int fd, _Out_writes_bytes_(nbyte) void *buf, size_t nbyte, off_t offset ); } 476 AUE_PWRITE STD|CAPENABLED { ssize_t pwrite( int fd, _In_reads_bytes_(nbyte) const void *buf, size_t nbyte, off_t offset ); } 477 AUE_MMAP STD|CAPENABLED { void *mmap( _In_ void *addr, size_t len, int prot, int flags, int fd, off_t pos ); } 478 AUE_LSEEK STD|CAPENABLED { off_t lseek( int fd, off_t offset, int whence ); } 479 AUE_TRUNCATE STD { int truncate( _In_z_ const char *path, off_t length ); } 480 AUE_FTRUNCATE STD|CAPENABLED { int ftruncate( int fd, off_t length ); } 481 AUE_THR_KILL2 STD { int thr_kill2( pid_t pid, long id, int sig ); } 482 AUE_SHMOPEN COMPAT12|CAPENABLED { int shm_open( _In_z_ const char *path, int flags, mode_t mode ); } 483 AUE_SHMUNLINK STD { int shm_unlink( _In_z_ const char *path ); } 484 AUE_NULL STD { int cpuset( _Out_ cpusetid_t *setid ); } 485 AUE_NULL STD { int cpuset_setid( cpuwhich_t which, id_t id, cpusetid_t setid ); } 486 AUE_NULL STD { int cpuset_getid( cpulevel_t level, cpuwhich_t which, id_t id, _Out_ cpusetid_t *setid ); } 487 AUE_NULL STD|CAPENABLED { int cpuset_getaffinity( cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, _Out_ cpuset_t *mask ); } 488 AUE_NULL STD|CAPENABLED { int cpuset_setaffinity( cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, _Out_ const cpuset_t *mask ); } 489 AUE_FACCESSAT STD|CAPENABLED { int faccessat( int fd, _In_z_ const char *path, int amode, int flag ); } 490 AUE_FCHMODAT STD|CAPENABLED { int fchmodat( int fd, _In_z_ const char *path, mode_t mode, int flag ); } 491 AUE_FCHOWNAT STD|CAPENABLED { int fchownat( int fd, _In_z_ const char *path, uid_t uid, gid_t gid, int flag ); } 492 AUE_FEXECVE STD|CAPENABLED { int fexecve( int fd, _In_ char **argv, _In_ char **envv ); } 493 AUE_FSTATAT COMPAT11|CAPENABLED { int fstatat( int fd, _In_z_ const char *path, _Out_ _Contains_long_timet_ struct freebsd11_stat *buf, int flag ); } 494 AUE_FUTIMESAT STD|CAPENABLED { int futimesat( int fd, _In_z_ const char *path, _In_reads_(2) _Contains_long_timet_ const struct timeval *times ); } 495 AUE_LINKAT STD|CAPENABLED { int linkat( int fd1, _In_z_ const char *path1, int fd2, _In_z_ const char *path2, int flag ); } 496 AUE_MKDIRAT STD|CAPENABLED { int mkdirat( int fd, _In_z_ const char *path, mode_t mode ); } 497 AUE_MKFIFOAT STD|CAPENABLED { int mkfifoat( int fd, _In_z_ const char *path, mode_t mode ); } 498 AUE_MKNODAT COMPAT11|CAPENABLED { int mknodat( int fd, _In_z_ const char *path, mode_t mode, uint32_t dev ); } ; XXX: see the comment for open 499 AUE_OPENAT_RWTC STD|CAPENABLED { int openat( int fd, _In_z_ const char *path, int flag, mode_t mode ); } 500 AUE_READLINKAT STD|CAPENABLED { ssize_t readlinkat( int fd, _In_z_ const char *path, _Out_writes_bytes_(bufsize) char *buf, size_t bufsize ); } 501 AUE_RENAMEAT STD|CAPENABLED { int renameat( int oldfd, _In_z_ const char *old, int newfd, _In_z_ const char *new ); } 502 AUE_SYMLINKAT STD|CAPENABLED { int symlinkat( _In_z_ const char *path1, int fd, _In_z_ const char *path2 ); } 503 AUE_UNLINKAT STD|CAPENABLED { int unlinkat( int fd, _In_z_ const char *path, int flag ); } 504 AUE_POSIX_OPENPT STD { int posix_openpt( int flags ); } ; 505 is initialised by the kgssapi code, if present. 505 AUE_NULL NOSTD { int gssd_syscall( _In_z_ const char *path ); } 506 AUE_JAIL_GET STD { int jail_get( _In_reads_(iovcnt) _Contains_long_ptr_ struct iovec *iovp, unsigned int iovcnt, int flags ); } 507 AUE_JAIL_SET STD { int jail_set( _In_reads_(iovcnt) _Contains_long_ptr_ struct iovec *iovp, unsigned int iovcnt, int flags ); } 508 AUE_JAIL_REMOVE STD { int jail_remove( int jid ); } 509 AUE_CLOSEFROM COMPAT12|CAPENABLED { int closefrom( int lowfd ); } 510 AUE_SEMCTL NOSTD { int __semctl( int semid, int semnum, int cmd, _Inout_ _Contains_ptr_ union semun *arg ); } 511 AUE_MSGCTL NOSTD { int msgctl( int msqid, int cmd, _Inout_opt_ _Contains_long_ptr_ struct msqid_ds *buf ); } 512 AUE_SHMCTL NOSTD { int shmctl( int shmid, int cmd, _Inout_opt_ _Contains_long_ struct shmid_ds *buf ); } 513 AUE_LPATHCONF STD { int lpathconf( _In_z_ const char *path, int name ); } 514 AUE_NULL OBSOL cap_new 515 AUE_CAP_RIGHTS_GET STD|CAPENABLED { int __cap_rights_get( int version, int fd, _Out_ cap_rights_t *rightsp ); } 516 AUE_CAP_ENTER STD|CAPENABLED { int cap_enter(void); } 517 AUE_CAP_GETMODE STD|CAPENABLED { int cap_getmode( _Out_ u_int *modep ); } 518 AUE_PDFORK STD|CAPENABLED { int pdfork( _Out_ int *fdp, int flags ); } 519 AUE_PDKILL STD|CAPENABLED { int pdkill( int fd, int signum ); } 520 AUE_PDGETPID STD|CAPENABLED { int pdgetpid( int fd, _Out_ pid_t *pidp ); } 521 AUE_NULL RESERVED 522 AUE_SELECT STD|CAPENABLED { int pselect( int nd, _Inout_opt_ fd_set *in, _Inout_opt_ fd_set *ou, _Inout_opt_ fd_set *ex, _In_opt_ _Contains_long_timet_ const struct timespec *ts, _In_opt_ const sigset_t *sm ); } 523 AUE_GETLOGINCLASS STD|CAPENABLED { int getloginclass( _Out_writes_z_(namelen) char *namebuf, size_t namelen ); } 524 AUE_SETLOGINCLASS STD { int setloginclass( _In_z_ const char *namebuf ); } 525 AUE_NULL STD { int rctl_get_racct( _In_reads_bytes_(inbuflen) const void *inbufp, size_t inbuflen, _Out_writes_bytes_(outbuflen) void *outbufp, size_t outbuflen ); } 526 AUE_NULL STD { int rctl_get_rules( _In_reads_bytes_(inbuflen) const void *inbufp, size_t inbuflen, _Out_writes_bytes_(outbuflen) void *outbufp, size_t outbuflen ); } 527 AUE_NULL STD { int rctl_get_limits( _In_reads_bytes_(inbuflen) const void *inbufp, size_t inbuflen, _Out_writes_bytes_(outbuflen) void *outbufp, size_t outbuflen ); } 528 AUE_NULL STD { int rctl_add_rule( _In_reads_bytes_(inbuflen) const void *inbufp, size_t inbuflen, _Out_writes_bytes_(outbuflen) void *outbufp, size_t outbuflen ); } 529 AUE_NULL STD { int rctl_remove_rule( _In_reads_bytes_(inbuflen) const void *inbufp, size_t inbuflen, _Out_writes_bytes_(outbuflen) void *outbufp, size_t outbuflen ); } 530 AUE_POSIX_FALLOCATE STD|CAPENABLED { int posix_fallocate( int fd, off_t offset, off_t len ); } 531 AUE_POSIX_FADVISE STD|CAPENABLED { int posix_fadvise( int fd, off_t offset, off_t len, int advice ); } 532 AUE_WAIT6 STD { int wait6( idtype_t idtype, id_t id, _Out_opt_ int *status, int options, _Out_opt_ _Contains_long_ struct __wrusage *wrusage, _Out_opt_ _Contains_long_ptr_ struct siginfo *info ); } 533 AUE_CAP_RIGHTS_LIMIT STD|CAPENABLED { int cap_rights_limit( int fd, _In_ cap_rights_t *rightsp ); } 534 AUE_CAP_IOCTLS_LIMIT STD|CAPENABLED { int cap_ioctls_limit( int fd, _In_reads_(ncmds) const u_long *cmds, size_t ncmds ); } 535 AUE_CAP_IOCTLS_GET STD|CAPENABLED { ssize_t cap_ioctls_get( int fd, _Out_writes_(maxcmds) u_long *cmds, size_t maxcmds ); } 536 AUE_CAP_FCNTLS_LIMIT STD|CAPENABLED { int cap_fcntls_limit( int fd, uint32_t fcntlrights ); } 537 AUE_CAP_FCNTLS_GET STD|CAPENABLED { int cap_fcntls_get( int fd, _Out_ uint32_t *fcntlrightsp ); } 538 AUE_BINDAT STD|CAPENABLED { int bindat( int fd, int s, _In_reads_bytes_(namelen) const struct sockaddr *name, __socklen_t namelen ); } 539 AUE_CONNECTAT STD|CAPENABLED { int connectat( int fd, int s, _In_reads_bytes_(namelen) const struct sockaddr *name, __socklen_t namelen ); } 540 AUE_CHFLAGSAT STD|CAPENABLED { int chflagsat( int fd, _In_z_ const char *path, u_long flags, int atflag ); } 541 AUE_ACCEPT STD|CAPENABLED { int accept4( int s, _Out_writes_bytes_opt_(*anamelen) struct sockaddr *name, _Inout_opt_ __socklen_t *anamelen, int flags ); } 542 AUE_PIPE STD|CAPENABLED { int pipe2( _Out_writes_(2) int *fildes, int flags ); } 543 AUE_AIO_MLOCK STD { int aio_mlock( _In_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 544 AUE_PROCCTL STD { int procctl( idtype_t idtype, id_t id, int com, _In_opt_ void *data ); } 545 AUE_POLL STD|CAPENABLED { int ppoll( _Inout_updates_(nfds) struct pollfd *fds, u_int nfds, _In_opt_ _Contains_long_timet_ const struct timespec *ts, _In_opt_ const sigset_t *set ); } 546 AUE_FUTIMES STD|CAPENABLED { int futimens( int fd, _In_reads_(2) _Contains_long_timet_ const struct timespec *times ); } 547 AUE_FUTIMESAT STD|CAPENABLED { int utimensat( int fd, _In_z_ const char *path, _In_reads_(2) _Contains_long_timet_ const struct timespec *times, int flag ); } 548 AUE_NULL OBSOL numa_getaffinity 549 AUE_NULL OBSOL numa_setaffinity 550 AUE_FSYNC STD|CAPENABLED { int fdatasync( int fd ); } 551 AUE_FSTAT STD|CAPENABLED { int fstat( int fd, _Out_ _Contains_long_timet_ struct stat *sb ); } 552 AUE_FSTATAT STD|CAPENABLED { int fstatat( int fd, _In_z_ const char *path, _Out_ _Contains_long_timet_ struct stat *buf, int flag ); } 553 AUE_FHSTAT STD { int fhstat( _In_ const struct fhandle *u_fhp, _Out_ _Contains_long_timet_ struct stat *sb ); } 554 AUE_GETDIRENTRIES STD|CAPENABLED { ssize_t getdirentries( int fd, _Out_writes_bytes_(count) char *buf, size_t count, _Out_ off_t *basep ); } 555 AUE_STATFS STD { int statfs( _In_z_ const char *path, _Out_ struct statfs *buf ); } 556 AUE_FSTATFS STD|CAPENABLED { int fstatfs( int fd, _Out_ struct statfs *buf ); } 557 AUE_GETFSSTAT STD { int getfsstat( _Out_writes_bytes_opt_(bufsize) struct statfs *buf, long bufsize, int mode ); } 558 AUE_FHSTATFS STD { int fhstatfs( _In_ const struct fhandle *u_fhp, _Out_ struct statfs *buf ); } 559 AUE_MKNODAT STD|CAPENABLED { int mknodat( int fd, _In_z_ const char *path, mode_t mode, dev_t dev ); } 560 AUE_KEVENT STD|CAPENABLED { int kevent( int fd, _In_reads_opt_(nchanges) _Contains_ptr_ const struct kevent *changelist, int nchanges, _Out_writes_opt_(nevents) _Contains_ptr_ struct kevent *eventlist, int nevents, _In_opt_ _Contains_long_timet_ const struct timespec *timeout ); } 561 AUE_NULL STD|CAPENABLED { int cpuset_getdomain( cpulevel_t level, cpuwhich_t which, id_t id, size_t domainsetsize, _Out_writes_bytes_(domainsetsize) domainset_t *mask, _Out_ int *policy ); } 562 AUE_NULL STD|CAPENABLED { int cpuset_setdomain( cpulevel_t level, cpuwhich_t which, id_t id, size_t domainsetsize, _In_ domainset_t *mask, int policy ); } 563 AUE_NULL STD|CAPENABLED { int getrandom( _Out_writes_bytes_(buflen) void *buf, size_t buflen, unsigned int flags ); } 564 AUE_NULL STD { int getfhat( int fd, _In_z_ char *path, _Out_ struct fhandle *fhp, int flags ); } 565 AUE_NULL STD { int fhlink( _In_ struct fhandle *fhp, _In_z_ const char *to ); } 566 AUE_NULL STD { int fhlinkat( _In_ struct fhandle *fhp, int tofd, _In_z_ const char *to, ); } 567 AUE_NULL STD { int fhreadlink( _In_ struct fhandle *fhp, _Out_writes_(bufsize) char *buf, size_t bufsize ); } 568 AUE_UNLINKAT STD|CAPENABLED { int funlinkat( int dfd, _In_z_ const char *path, int fd, int flag ); } 569 AUE_NULL STD|CAPENABLED { ssize_t copy_file_range( int infd, _Inout_opt_ off_t *inoffp, int outfd, _Inout_opt_ off_t *outoffp, size_t len, unsigned int flags ); } 570 AUE_SYSCTL STD|CAPENABLED { int __sysctlbyname( _In_reads_(namelen) const char *name, size_t namelen, _Out_writes_bytes_opt_(*oldlenp) void *old, _Inout_opt_ size_t *oldlenp, _In_reads_bytes_opt_(newlen) void *new, size_t newlen ); } 571 AUE_SHMOPEN STD|CAPENABLED { int shm_open2( _In_z_ const char *path, int flags, mode_t mode, int shmflags, _In_z_ const char *name ); } 572 AUE_SHMRENAME STD { int shm_rename( _In_z_ const char *path_from, _In_z_ const char *path_to, int flags ); } 573 AUE_NULL STD|CAPENABLED { int sigfastblock( int cmd, _Inout_opt_ uint32_t *ptr ); } 574 AUE_REALPATHAT STD { int __realpathat( int fd, _In_z_ const char *path, _Out_writes_z_(size) char *buf, size_t size, int flags ); } 575 AUE_CLOSERANGE STD|CAPENABLED { int close_range( u_int lowfd, u_int highfd, int flags ); } ; 576 is initialised by the krpc code, if present. 576 AUE_NULL NOSTD { int rpctls_syscall( int op, _In_z_ const char *path ); } 577 AUE_SPECIALFD STD|CAPENABLED { int __specialfd( int type, _In_reads_bytes_(len) const void *req, size_t len ); } 578 AUE_AIO_WRITEV STD|CAPENABLED { int aio_writev( _Inout_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 579 AUE_AIO_READV STD|CAPENABLED { int aio_readv( _Inout_ _Contains_long_ptr_ struct aiocb *aiocbp ); } 580 AUE_FSPACECTL STD|CAPENABLED { int fspacectl( int fd, int cmd, _In_ const struct spacectl_range *rqsr, int flags, _Out_opt_ struct spacectl_range *rmsr, ); } 581 AUE_NULL STD|CAPENABLED { int sched_getcpu(void); } 582 AUE_SWAPOFF STD { int swapoff( _In_z_ const char *name, u_int flags, ); } 583 AUE_KQUEUE STD|CAPENABLED { - int kqueue1( + int kqueuex( u_int flags ); } ; vim: syntax=off diff --git a/sys/sys/event.h b/sys/sys/event.h index a2c0d481ebb2..b902f195723e 100644 --- a/sys/sys/event.h +++ b/sys/sys/event.h @@ -1,372 +1,372 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1999,2000,2001 Jonathan Lemon * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_EVENT_H_ #define _SYS_EVENT_H_ #include #include #define EVFILT_READ (-1) #define EVFILT_WRITE (-2) #define EVFILT_AIO (-3) /* attached to aio requests */ #define EVFILT_VNODE (-4) /* attached to vnodes */ #define EVFILT_PROC (-5) /* attached to struct proc */ #define EVFILT_SIGNAL (-6) /* attached to struct proc */ #define EVFILT_TIMER (-7) /* timers */ #define EVFILT_PROCDESC (-8) /* attached to process descriptors */ #define EVFILT_FS (-9) /* filesystem events */ #define EVFILT_LIO (-10) /* attached to lio requests */ #define EVFILT_USER (-11) /* User events */ #define EVFILT_SENDFILE (-12) /* attached to sendfile requests */ #define EVFILT_EMPTY (-13) /* empty send socket buf */ #define EVFILT_SYSCOUNT 13 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #define EV_SET(kevp_, a, b, c, d, e, f) do { \ *(kevp_) = (struct kevent){ \ .ident = (a), \ .filter = (b), \ .flags = (c), \ .fflags = (d), \ .data = (e), \ .udata = (f), \ .ext = {0}, \ }; \ } while (0) #else /* Pre-C99 or not STDC (e.g., C++) */ /* * The definition of the local variable kevp could possibly conflict * with a user-defined value passed in parameters a-f. */ #define EV_SET(kevp_, a, b, c, d, e, f) do { \ struct kevent *kevp = (kevp_); \ (kevp)->ident = (a); \ (kevp)->filter = (b); \ (kevp)->flags = (c); \ (kevp)->fflags = (d); \ (kevp)->data = (e); \ (kevp)->udata = (f); \ (kevp)->ext[0] = 0; \ (kevp)->ext[1] = 0; \ (kevp)->ext[2] = 0; \ (kevp)->ext[3] = 0; \ } while (0) #endif struct kevent { __uintptr_t ident; /* identifier for this event */ short filter; /* filter for event */ unsigned short flags; /* action flags for kqueue */ unsigned int fflags; /* filter flag value */ __int64_t data; /* filter data value */ void *udata; /* opaque user data identifier */ __uint64_t ext[4]; /* extensions */ }; #if defined(_WANT_FREEBSD11_KEVENT) /* Older structure used in FreeBSD 11.x and older. */ struct freebsd11_kevent { __uintptr_t ident; /* identifier for this event */ short filter; /* filter for event */ unsigned short flags; unsigned int fflags; __intptr_t data; void *udata; /* opaque user data identifier */ }; #endif #if defined(_WANT_KEVENT32) || (defined(_KERNEL) && defined(__LP64__)) struct kevent32 { __uint32_t ident; /* identifier for this event */ short filter; /* filter for event */ unsigned short flags; unsigned int fflags; #ifndef __amd64__ __uint32_t pad0; #endif __uint32_t data1, data2; __uint32_t udata; /* opaque user data identifier */ #ifndef __amd64__ __uint32_t pad1; #endif __uint32_t ext64[8]; }; #ifdef _WANT_FREEBSD11_KEVENT struct freebsd11_kevent32 { __uint32_t ident; /* identifier for this event */ short filter; /* filter for event */ unsigned short flags; unsigned int fflags; __int32_t data; __uint32_t udata; /* opaque user data identifier */ }; #endif #endif /* actions */ #define EV_ADD 0x0001 /* add event to kq (implies enable) */ #define EV_DELETE 0x0002 /* delete event from kq */ #define EV_ENABLE 0x0004 /* enable event */ #define EV_DISABLE 0x0008 /* disable event (not reported) */ #define EV_FORCEONESHOT 0x0100 /* enable _ONESHOT and force trigger */ #define EV_KEEPUDATA 0x0200 /* do not update the udata field */ /* flags */ #define EV_ONESHOT 0x0010 /* only report one occurrence */ #define EV_CLEAR 0x0020 /* clear event state after reporting */ #define EV_RECEIPT 0x0040 /* force EV_ERROR on success, data=0 */ #define EV_DISPATCH 0x0080 /* disable event after reporting */ #define EV_SYSFLAGS 0xF000 /* reserved by system */ #define EV_DROP 0x1000 /* note should be dropped */ #define EV_FLAG1 0x2000 /* filter-specific flag */ #define EV_FLAG2 0x4000 /* filter-specific flag */ /* returned values */ #define EV_EOF 0x8000 /* EOF detected */ #define EV_ERROR 0x4000 /* error, data contains errno */ /* * data/hint flags/masks for EVFILT_USER, shared with userspace * * On input, the top two bits of fflags specifies how the lower twenty four * bits should be applied to the stored value of fflags. * * On output, the top two bits will always be set to NOTE_FFNOP and the * remaining twenty four bits will contain the stored fflags value. */ #define NOTE_FFNOP 0x00000000 /* ignore input fflags */ #define NOTE_FFAND 0x40000000 /* AND fflags */ #define NOTE_FFOR 0x80000000 /* OR fflags */ #define NOTE_FFCOPY 0xc0000000 /* copy fflags */ #define NOTE_FFCTRLMASK 0xc0000000 /* masks for operations */ #define NOTE_FFLAGSMASK 0x00ffffff #define NOTE_TRIGGER 0x01000000 /* Cause the event to be triggered for output. */ /* * data/hint flags for EVFILT_{READ|WRITE}, shared with userspace */ #define NOTE_LOWAT 0x0001 /* low water mark */ #define NOTE_FILE_POLL 0x0002 /* behave like poll() */ /* * data/hint flags for EVFILT_VNODE, shared with userspace */ #define NOTE_DELETE 0x0001 /* vnode was removed */ #define NOTE_WRITE 0x0002 /* data contents changed */ #define NOTE_EXTEND 0x0004 /* size increased */ #define NOTE_ATTRIB 0x0008 /* attributes changed */ #define NOTE_LINK 0x0010 /* link count changed */ #define NOTE_RENAME 0x0020 /* vnode was renamed */ #define NOTE_REVOKE 0x0040 /* vnode access was revoked */ #define NOTE_OPEN 0x0080 /* vnode was opened */ #define NOTE_CLOSE 0x0100 /* file closed, fd did not allowed write */ #define NOTE_CLOSE_WRITE 0x0200 /* file closed, fd did allowed write */ #define NOTE_READ 0x0400 /* file was read */ /* * data/hint flags for EVFILT_PROC and EVFILT_PROCDESC, shared with userspace */ #define NOTE_EXIT 0x80000000 /* process exited */ #define NOTE_FORK 0x40000000 /* process forked */ #define NOTE_EXEC 0x20000000 /* process exec'd */ #define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */ #define NOTE_PDATAMASK 0x000fffff /* mask for pid */ /* additional flags for EVFILT_PROC */ #define NOTE_TRACK 0x00000001 /* follow across forks */ #define NOTE_TRACKERR 0x00000002 /* could not track child */ #define NOTE_CHILD 0x00000004 /* am a child process */ /* additional flags for EVFILT_TIMER */ #define NOTE_SECONDS 0x00000001 /* data is seconds */ #define NOTE_MSECONDS 0x00000002 /* data is milliseconds */ #define NOTE_USECONDS 0x00000004 /* data is microseconds */ #define NOTE_NSECONDS 0x00000008 /* data is nanoseconds */ #define NOTE_ABSTIME 0x00000010 /* timeout is absolute */ -/* Flags for kqueue1(2) */ +/* Flags for kqueuex(2) */ #define KQUEUE_CLOEXEC 0x00000001 /* close on exec */ struct knote; SLIST_HEAD(klist, knote); struct kqueue; TAILQ_HEAD(kqlist, kqueue); struct knlist { struct klist kl_list; void (*kl_lock)(void *); /* lock function */ void (*kl_unlock)(void *); void (*kl_assert_lock)(void *, int); void *kl_lockarg; /* argument passed to lock functions */ int kl_autodestroy; }; #ifdef _KERNEL /* * Flags for knote call */ #define KNF_LISTLOCKED 0x0001 /* knlist is locked */ #define KNF_NOKQLOCK 0x0002 /* do not keep KQ_LOCK */ #define KNOTE(list, hint, flags) knote(list, hint, flags) #define KNOTE_LOCKED(list, hint) knote(list, hint, KNF_LISTLOCKED) #define KNOTE_UNLOCKED(list, hint) knote(list, hint, 0) #define KNLIST_EMPTY(list) SLIST_EMPTY(&(list)->kl_list) /* * Flag indicating hint is a signal. Used by EVFILT_SIGNAL, and also * shared by EVFILT_PROC (all knotes attached to p->p_klist) */ #define NOTE_SIGNAL 0x08000000 /* * Hint values for the optional f_touch event filter. If f_touch is not set * to NULL and f_isfd is zero the f_touch filter will be called with the type * argument set to EVENT_REGISTER during a kevent() system call. It is also * called under the same conditions with the type argument set to EVENT_PROCESS * when the event has been triggered. */ #define EVENT_REGISTER 1 #define EVENT_PROCESS 2 struct filterops { int f_isfd; /* true if ident == filedescriptor */ int (*f_attach)(struct knote *kn); void (*f_detach)(struct knote *kn); int (*f_event)(struct knote *kn, long hint); void (*f_touch)(struct knote *kn, struct kevent *kev, u_long type); }; /* * An in-flux knote cannot be dropped from its kq while the kq is * unlocked. If the KN_SCAN flag is not set, a thread can only set * kn_influx when it is exclusive owner of the knote state, and can * modify kn_status as if it had the KQ lock. KN_SCAN must not be set * on a knote which is already in flux. * * kn_sfflags, kn_sdata, and kn_kevent are protected by the knlist lock. */ struct knote { SLIST_ENTRY(knote) kn_link; /* for kq */ SLIST_ENTRY(knote) kn_selnext; /* for struct selinfo */ struct knlist *kn_knlist; /* f_attach populated */ TAILQ_ENTRY(knote) kn_tqe; struct kqueue *kn_kq; /* which queue we are on */ struct kevent kn_kevent; void *kn_hook; int kn_hookid; int kn_status; /* protected by kq lock */ #define KN_ACTIVE 0x01 /* event has been triggered */ #define KN_QUEUED 0x02 /* event is on queue */ #define KN_DISABLED 0x04 /* event is disabled */ #define KN_DETACHED 0x08 /* knote is detached */ #define KN_MARKER 0x20 /* ignore this knote */ #define KN_KQUEUE 0x40 /* this knote belongs to a kq */ #define KN_SCAN 0x100 /* flux set in kqueue_scan() */ int kn_influx; int kn_sfflags; /* saved filter flags */ int64_t kn_sdata; /* saved data field */ union { struct file *p_fp; /* file data pointer */ struct proc *p_proc; /* proc pointer */ struct kaiocb *p_aio; /* AIO job pointer */ struct aioliojob *p_lio; /* LIO job pointer */ void *p_v; /* generic other pointer */ } kn_ptr; struct filterops *kn_fop; #define kn_id kn_kevent.ident #define kn_filter kn_kevent.filter #define kn_flags kn_kevent.flags #define kn_fflags kn_kevent.fflags #define kn_data kn_kevent.data #define kn_fp kn_ptr.p_fp }; struct kevent_copyops { void *arg; int (*k_copyout)(void *arg, struct kevent *kevp, int count); int (*k_copyin)(void *arg, struct kevent *kevp, int count); size_t kevent_size; }; struct thread; struct proc; struct knlist; struct mtx; struct rwlock; void knote(struct knlist *list, long hint, int lockflags); void knote_fork(struct knlist *list, int pid); struct knlist *knlist_alloc(struct mtx *lock); void knlist_detach(struct knlist *knl); void knlist_add(struct knlist *knl, struct knote *kn, int islocked); void knlist_remove(struct knlist *knl, struct knote *kn, int islocked); int knlist_empty(struct knlist *knl); void knlist_init(struct knlist *knl, void *lock, void (*kl_lock)(void *), void (*kl_unlock)(void *), void (*kl_assert_lock)(void *, int)); void knlist_init_mtx(struct knlist *knl, struct mtx *lock); void knlist_destroy(struct knlist *knl); void knlist_cleardel(struct knlist *knl, struct thread *td, int islocked, int killkn); #define knlist_clear(knl, islocked) \ knlist_cleardel((knl), NULL, (islocked), 0) #define knlist_delete(knl, td, islocked) \ knlist_cleardel((knl), (td), (islocked), 1) void knote_fdclose(struct thread *p, int fd); int kqfd_register(int fd, struct kevent *kev, struct thread *p, int mflag); int kqueue_add_filteropts(int filt, struct filterops *filtops); int kqueue_del_filteropts(int filt); void kqueue_drain_schedtask(void); #else /* !_KERNEL */ #include struct timespec; __BEGIN_DECLS int kqueue(void); -int kqueue1(unsigned flags); +int kqueuex(unsigned flags); int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); __END_DECLS #endif /* !_KERNEL */ #endif /* !_SYS_EVENT_H_ */