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 my $foo = [ $idx + 0 ];
84 return (0, $foo->[0]);
88 my ($path, $flags, $fh) = @_;
89 print 'called ', (caller(0))[3], "\n";
91 #$fh = fsel_path_index($path);
93 $fsel_open_mask &= ~(1 << $fh);
98 my ($path, $size, $offset, $fh) = @_;
99 print 'called ', (caller(0))[3], "\n";
101 #$fh = fsel_path_index($path);
104 if ($fsel_cnt[$fh] < $size) {
105 $size = $fsel_cnt[$fh];
107 printf("READ \%X transferred=\%u cnt=\%u\n", $fh, $size, $fsel_cnt[$fh]);
108 $fsel_cnt[$fh] -= $size;
110 return(chr($fh) x $size);
113 our $polled_zero :shared = 0;
116 my ($path, $ph, $revents, $fh) = @_;
117 print 'called ', (caller(0))[3], ", path = \"$path\", fh = $fh, revents = $revents\n";
119 #$fh = fsel_path_index($path);
124 my $oldph = $fsel_poll_handle[$fh];
126 pollhandle_destroy($oldph);
128 $fsel_poll_notify_mask |= (1 << $fh);
129 $fsel_poll_handle[$fh] = $ph;
132 if ($fsel_cnt[$fh]) {
134 printf("POLL \%X cnt=\%u polled_zero=\%u\n", $fh, $fsel_cnt[$fh],
146 print 'called ', (caller(0))[3], "\n";
147 local $SIG{'KILL'} = sub { threads->exit(); };
157 for (($i, $t) = (0, $idx); $i < $nr; $i++,
158 $t = (($t + int(FSEL_FILES / $nr)) % FSEL_FILES)) {
159 next if $fsel_cnt[$t] == FSEL_CNT_MAX;
162 if ($fsel_poll_notify_mask & (1 << $t)) {
163 printf("NOTIFY \%X\n", $t);
164 my $ph = $fsel_poll_handle[$t];
166 pollhandle_destroy($ph);
167 $fsel_poll_handle[$t] = undef;
168 $fsel_poll_notify_mask &= ~(1 << $t);
172 $idx = ($idx + 1) % FSEL_FILES;
182 croak("Fuse doesn't have poll") unless Fuse::fuse_version() >= 2.8;
185 'mountpoint' => $ARGV[0],
186 'getattr' => 'main::fsel_getattr',
187 'readdir' => 'main::fsel_readdir',
188 'open' => 'main::fsel_open',
189 'release' => 'main::fsel_release',
190 'read' => 'main::fsel_read',
191 'poll' => 'main::fsel_poll',
195 'use-threads' => sub {
196 print STDERR "Warning: Fuse currently has bugs related to threading which may cause misbehavior\n";
197 $fuseargs{'threaded'} = 1;
200 $fuseargs{'debug'} = 1;
202 ) || croak("Malformed options passed");
204 my $thread = threads->create(\&fsel_producer);
206 Fuse::main(%fuseargs);
208 $thread->kill('KILL');