10 local $SIG{'__WARN__'} = \&Carp::cluck;
15 use IO::Poll qw(POLLIN);
16 use Time::HiRes qw(sleep);
19 use constant FSEL_CNT_MAX => 10;
20 use constant FSEL_FILES => 16;
22 my $fsel_open_mask :shared = 0;
23 my $fsel_poll_notify_mask :shared = 0;
24 my @fsel_poll_handle :shared;
26 map { $fsel_cnt[$_] = 0 } (0 .. (FSEL_FILES - 1));
28 my $fsel_mutex :shared;
32 print 'called ', (caller(0))[3], "\n";
34 my $ch = substr($path, 1, 1);
35 if (length($path) != 2 || substr($path, 0, 1) ne '/' ||
36 $ch !~ /^[0-9A-F]$/) {
44 print 'called ', (caller(0))[3], "\n";
45 my @stbuf = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
48 $stbuf[2] = S_IFDIR | 0555;
53 my $idx = fsel_path_index($path);
54 return -&ENOENT if $idx < 0;
56 $stbuf[2] = S_IFREG | 0444;
58 $stbuf[7] = $fsel_cnt[$idx];
63 my ($path, $offset) = @_;
64 print 'called ', (caller(0))[3], "\n";
66 return -&ENOENT if $path ne '/';
68 return('.', '..', map { sprintf('%X', $_) } (0 .. (FSEL_FILES - 1)), 0);
72 my ($path, $flags, $info) = @_;
73 print 'called ', (caller(0))[3], "\n";
75 my $idx = fsel_path_index($path);
76 return -&ENOENT if $idx < 0;
77 return -&EACCES if $flags & 3 != O_RDONLY;
78 return -&EBUSY if $fsel_open_mask & (1 << $idx);
79 $fsel_open_mask |= (1 << $idx);
81 $info->{'direct_io'} = 1;
82 $info->{'nonseekable'} = 1;
83 print "fsel_open(): ", $idx, "\n";
84 my $foo = [ $idx + 0 ];
85 return (0, $foo->[0]);
89 my ($path, $flags, $fh) = @_;
90 print 'called ', (caller(0))[3], "\n";
92 print "fsel_release(): \$fh is $fh\n";
93 $fsel_open_mask &= ~(1 << $fh);
94 printf("fsel_release(): \$fsel_open_mask is \%x\n", $fsel_open_mask);
99 my ($path, $size, $offset, $fh) = @_;
100 print 'called ', (caller(0))[3], "\n";
103 if ($fsel_cnt[$fh] < $size) {
104 $size = $fsel_cnt[$fh];
106 printf("READ \%X transferred=\%u cnt=\%u\n", $fh, $size, $fsel_cnt[$fh]);
107 $fsel_cnt[$fh] -= $size;
109 return(chr($fh) x $size);
112 our $polled_zero :shared = 0;
115 my ($path, $ph, $revents, $fh) = @_;
116 print 'called ', (caller(0))[3], "\n";
121 my $oldph = $fsel_poll_handle[$fh];
123 pollhandle_destroy($oldph);
125 $fsel_poll_notify_mask |= (1 << $fh);
126 $fsel_poll_handle[$fh] = $ph;
129 if ($fsel_cnt[$fh]) {
131 printf("POLL \%X cnt=\%u polled_zero=\%u\n", $fh, $fsel_cnt[$fh],
143 local $SIG{'KILL'} = sub { threads->exit(); };
144 print 'called ', (caller(0))[3], "\n";
154 for (($i, $t) = (0, $idx); $i < $nr; $i++,
155 $t = (($t + int(FSEL_FILES / $nr)) % FSEL_FILES)) {
156 next if $fsel_cnt[$t] == FSEL_CNT_MAX;
159 if ($fsel_poll_notify_mask & (1 << $t)) {
160 printf("NOTIFY \%X\n", $t);
161 my $ph = $fsel_poll_handle[$t];
163 pollhandle_destroy($ph);
164 $fsel_poll_handle[$t] = undef;
165 $fsel_poll_notify_mask &= ~(1 << $t);
169 $idx = ($idx + 1) % FSEL_FILES;
179 croak("Fuse doesn't have poll") unless Fuse::fuse_version() >= 2.8;
181 my $thread = threads->create(\&fsel_producer);
184 'mountpoint' => $ARGV[0],
185 'getattr' => 'main::fsel_getattr',
186 'readdir' => 'main::fsel_readdir',
187 'open' => 'main::fsel_open',
188 'release' => 'main::fsel_release',
189 'read' => 'main::fsel_read',
190 'poll' => 'main::fsel_poll',
194 $thread->kill('KILL');