#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
+#if defined(__FreeBSD__) && __FreeBSD__ >= 15
+# define HAZ_INOTIFY
+# include <sys/inotify.h>
+# include <sys/specialfd.h>
+#endif
#ifdef __linux__
+# define HAZ_INOTIFY
# include <linux/fs.h>
# include <sys/epoll.h>
# include <sys/inotify.h>
printf("'sizeof(size_t)' => %zu,\n", sizeof(size_t));
printf("'sizeof(off_t)' => %zu,\n", sizeof(off_t));
-#ifdef __linux__
- D(SYS_epoll_create1);
- D(SYS_epoll_ctl);
- MAYBE D(SYS_epoll_pwait);
-
+#ifdef HAZ_INOTIFY
+ D(SYS_inotify_rm_watch);
+ X(IN_NONBLOCK);
X(IN_CLOEXEC);
X(IN_ACCESS);
X(IN_ALL_EVENTS);
X(IN_OPEN);
X(IN_Q_OVERFLOW);
X(IN_UNMOUNT);
+ STRUCT_BEGIN(struct inotify_event);
+ PR_NUM(wd);
+ PR_NUM(mask);
+ PR_NUM(cookie);
+ PR_NUM(len);
+ PR_OFF(name);
+ STRUCT_END;
+#endif /* HAZ_INOTIFY */
+
+#ifdef __linux__
+ D(SYS_epoll_create1);
+ D(SYS_epoll_ctl);
+ MAYBE D(SYS_epoll_pwait);
D(SYS_inotify_init1);
D(SYS_inotify_add_watch);
- D(SYS_inotify_rm_watch);
D(SYS_prctl);
D(SYS_fstatfs);
PR_NUM(data.u64);
STRUCT_END;
- STRUCT_BEGIN(struct inotify_event);
- PR_NUM(wd);
- PR_NUM(mask);
- PR_NUM(cookie);
- PR_NUM(len);
- PR_OFF(name);
- STRUCT_END;
-
STRUCT_BEGIN(struct statfs);
PR_NUM(f_type);
STRUCT_END;
#endif /* Linux, any other OSes with stable syscalls? */
+/* FreeBSD 15+ has inotify, maybe others will follow */
+#if defined(__FreeBSD__) && __FreeBSD__ >= 15
+ D(SYS___specialfd);
+ D(SPECIALFD_INOTIFY);
+ STRUCT_BEGIN(struct specialfd_inotify);
+ PR_NUM(flags);
+ STRUCT_END;
+ D(SYS_inotify_add_watch_at);
+ D(AT_FDCWD);
+#endif /* FreeBSD >= 15 */
+
D(SIGWINCH);
MAYBE X(FIONREAD);
MAYBE D(SO_ACCEPTFILTER);
# Implements most Linux::Inotify2 functionality we need in pure Perl
# Anonymous sub support isn't supported since it's expensive in the
-# best case and likely leaky in older Perls (e.g. 5.16.3)
+# best case and likely leaky in some Perls (e.g. 5.16.3, 5.40.x)
package PublicInbox::Inotify3;
use v5.12;
use autodie qw(open);
use constant $PublicInbox::Syscall::INOTIFY;
our %events;
-# extracted from devel/sysdefs-list output, these should be arch-independent
BEGIN {
+# extracted from devel/sysdefs-list output, these should be arch-independent
+# for Linux and also FreeBSD 15+
%events = (
IN_ACCESS => 0x1,
IN_ALL_EVENTS => 0xfff,
use constant autocancel =>
(IN_IGNORED|IN_UNMOUNT|IN_ONESHOT|IN_DELETE_SELF);
+if (defined $PublicInbox::Syscall::INOTIFY->{SYS_inotify_init1}) {
+ eval <<'EOS' or die $@;
+
sub new {
- open my $fh, '+<&=', syscall(SYS_inotify_init1, IN_CLOEXEC);
+ open my $fh, "+<&=", syscall SYS_inotify_init1, IN_CLOEXEC;
bless { fh => $fh }, __PACKAGE__;
}
+sub inotify_add_watch ($$$) { syscall SYS_inotify_add_watch, @_ }
+1;
+EOS
+} elsif (defined $PublicInbox::Syscall::INOTIFY->{SYS___specialfd}) {
+ eval <<'EOS' or die $@;
+sub new {
+ my $args = pack "L", IN_CLOEXEC; # struct specialfd_inotify
+ open my $fh, "+<&=", syscall SYS___specialfd, SPECIALFD_INOTIFY,
+ $args, length $args;
+ bless { fh => $fh }, __PACKAGE__;
+}
+sub inotify_add_watch ($$$) {
+ syscall SYS_inotify_add_watch_at, $_[0], AT_FDCWD, $_[1], $_[2];
+}
+1;
+EOS
+}
sub read {
my ($self) = @_;
my (@ret, $wd, $mask, $len, $name, $size, $buf);
sub watch {
my ($self, $name, $mask, $cb) = @_;
croak "E: $cb not supported" if $cb; # too much memory
- my $wd = syscall(SYS_inotify_add_watch, $self->fileno, $name, $mask);
+ my $wd = inotify_add_watch($self->fileno, $name, $mask);
return if $wd < 0;
my $w = bless [ $wd, $mask, $name, $self ], 'PublicInbox::In3Watch';
$self->{w}->{$wd} = $w;
my $SYS_fstatfs; # don't need fstatfs64, just statfs.f_type
my ($FS_IOC_GETFLAGS, $FS_IOC_SETFLAGS, $SYS_writev,
$BTRFS_IOC_DEFRAG);
+our ($machine, $kver);
my $SFD_CLOEXEC = 02000000; # Perl does not expose O_CLOEXEC
our $no_deprecated = 0;
+BEGIN {
+ (undef, undef, my $release, undef, $machine) = POSIX::uname();
+ ($kver) = ($release =~ /([0-9]+(?:\.(?:[0-9]+))+)/);
+ $kver = eval("v$kver") // die "bad release=$release from uname";
+}
if ($^O eq "linux") {
$F_SETPIPE_SZ = 1031;
- my (undef, undef, $release, undef, $machine) = POSIX::uname();
- my ($kver) = ($release =~ /([0-9]+(?:\.(?:[0-9]+))+)/);
- $kver = eval("v$kver") // v2.6;
$SYS_renameat2 = 0 if $kver lt v3.15;
$SYS_epoll_pwait = 0 if $kver lt v2.6.19;
# whether the machine requires 64-bit numbers to be on 8-byte
# so leave it unset on dfly
$CONST{TCP_ESTABLISHED} = 4 if $^O ne 'dragonfly';
}
+ if ($^O eq 'freebsd' && $kver ge v15.0) {
+ $INOTIFY = {
+ IN_CLOEXEC => 0x100000, # different from Linux :P
+ SYS___specialfd => 577,
+ AT_FDCWD => -100, # XXX we may use elsewhere
+ SPECIALFD_INOTIFY => 2,
+ SYS_inotify_add_watch_at => 593,
+ SYS_inotify_rm_watch => 594,
+ }
+ }
$CONST{CMSG_ALIGN_size} = SIZEOF_size_t;
$CONST{SIZEOF_cmsghdr} //= 0;
$CONST{TMPL_cmsg_len} //= undef;
use v5.12; use PublicInbox::TestCommon;
use Config;
use POSIX qw(uname);
-plan skip_all => 'inotify is Linux-only' if $^O ne 'linux';
+use PublicInbox::Syscall;
+plan skip_all => 'inotify is Linux and FreeBSD 15+ only'
+ unless $PublicInbox::Syscall::INOTIFY;
unless (eval { require PublicInbox::Inotify3 }) {
my (undef, undef, undef, undef, $machine) = uname();
diag '<cppsymbols>';