Code cleanups.
authorDerrik Pates <demon@now.ai>
Wed, 29 Feb 2012 00:20:24 +0000 (17:20 -0700)
committerDerrik Pates <demon@now.ai>
Wed, 29 Feb 2012 00:20:24 +0000 (17:20 -0700)
More perl-izing using list assignment and declaration.

Added more comments to clarify purpose of parts of code.

Tweaked layout a bit to match up better with the original C version
(mostly declaration/calling/assignment order bits here and there).

Separated %fuseargs declare/init from setting the 'mountpoint' element,
to better handle parsing options out before grabbing the mount point.

examples/fsel.pl

index 5d69902..f76255b 100755 (executable)
@@ -16,27 +16,33 @@ use IO::Poll qw(POLLIN);
 use Time::HiRes qw(sleep);
 use Getopt::Long;
 
+# $fsel_open_mask is used to limit the number of opens to 1 per file. This
+# uses the file index (0-F) as $fh, as poll support requires a unique handle
+# per open file. Lifting this would require more complete open file
+# management.
+my $fsel_open_mask :shared = 0;
+
+# Maximum "file" size.
 use constant FSEL_CNT_MAX   => 10;
 use constant FSEL_FILES     => 16;
 
-my $fsel_open_mask :shared = 0;
+# Used only as a lock for $fsel_poll_notify_mask and @fsel_cnt.
+my $fsel_mutex :shared;
+# Mask indicating what FDs have poll notifications waiting.
 my $fsel_poll_notify_mask :shared = 0;
+# Poll notification handles.
 my @fsel_poll_handle :shared;
+# Number of bytes for each "file".
 my @fsel_cnt :shared;
+# Initialize all byte counts.
 map { $fsel_cnt[$_] = 0 } (0 .. (FSEL_FILES - 1));
 
-my $fsel_mutex :shared;
-
 sub fsel_path_index {
     my ($path) = @_;
     print 'called ', (caller(0))[3], "\n";
 
-    my $ch = substr($path, 1, 1);
-    if (length($path) != 2 || substr($path, 0, 1) ne '/' || 
-            $ch !~ /^[0-9A-F]$/) {
-        return -1;
-    }
-    return hex($ch);
+    return -1 if $path !~ m{^/([0-9A-F])$};
+    return hex($1);
 }
 
 sub fsel_getattr {
@@ -45,17 +51,14 @@ sub fsel_getattr {
     my @stbuf = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
     if ($path eq '/') {
-        $stbuf[2] = S_IFDIR | 0555;
-        $stbuf[3] = 2;
+        @stbuf[2, 3] = (S_IFDIR | 0555, 2);
         return @stbuf;
     }
 
     my $idx = fsel_path_index($path);
     return -&ENOENT if $idx < 0;
 
-    $stbuf[2] = S_IFREG | 0444;
-    $stbuf[3] = 1;
-    $stbuf[7] = $fsel_cnt[$idx];
+    @stbuf[2, 3, 7] = (S_IFREG | 0444, 1, $fsel_cnt[$idx]);
     return @stbuf;
 }
 
@@ -74,21 +77,20 @@ sub fsel_open {
 
     my $idx = fsel_path_index($path);
     return -&ENOENT if $idx < 0;
-    return -&EACCES if $flags & 3 != O_RDONLY;
-    return -&EBUSY if $fsel_open_mask & (1 << $idx);
+    return -&EACCES if $flags & O_ACCMODE != O_RDONLY;
+    return -&EBUSY  if $fsel_open_mask & (1 << $idx);
     $fsel_open_mask |= (1 << $idx);
 
-    $info->{'direct_io'} = 1;
-    $info->{'nonseekable'} = 1;
-    my $foo = [ $idx + 0 ];
-    return (0, $foo->[0]);
+    # fsel files are nonseekable somewhat pipe-like files which get filled
+    # up periodically by the producer thread, and consumed on read. Tell
+    # FUSE to do this right.
+    @{$info}{'direct_io', 'nonseekable'} = (1, 1);
+    return (0, $idx);
 }
 
 sub fsel_release {
     my ($path, $flags, $fh) = @_;
     print 'called ', (caller(0))[3], "\n";
-    ## HACK
-    #$fh = fsel_path_index($path);
 
     $fsel_open_mask &= ~(1 << $fh);
     return 0;
@@ -97,8 +99,6 @@ sub fsel_release {
 sub fsel_read {
     my ($path, $size, $offset, $fh) = @_;
     print 'called ', (caller(0))[3], "\n";
-    ## HACK
-    #$fh = fsel_path_index($path);
     lock($fsel_mutex);
 
     if ($fsel_cnt[$fh] < $size) {
@@ -115,16 +115,12 @@ our $polled_zero :shared = 0;
 sub fsel_poll {
     my ($path, $ph, $revents, $fh) = @_;
     print 'called ', (caller(0))[3], ", path = \"$path\", fh = $fh, revents = $revents\n";
-    ## HACK
-    #$fh = fsel_path_index($path);
 
     lock($fsel_mutex);
 
     if ($ph) {
         my $oldph = $fsel_poll_handle[$fh];
-        if ($oldph) {
-            pollhandle_destroy($oldph);
-        }
+        pollhandle_destroy($oldph) if $oldph;
         $fsel_poll_notify_mask |= (1 << $fh);
         $fsel_poll_handle[$fh] = $ph;
     }
@@ -145,15 +141,16 @@ sub fsel_poll {
 sub fsel_producer {
     print 'called ', (caller(0))[3], "\n";
     local $SIG{'KILL'} = sub { threads->exit(); };
-    my $tv = 0.25;
-    my $idx = 0;
-    my $nr = 1;
+    my ($tv, $idx, $nr) = (0.25, 0, 1);
 
     while (1) {
         {
             my ($i, $t);
             lock($fsel_mutex);
 
+            # This is the main producer loop which is executed every 250
+            # msec. On each iteration, it adds one byte to 1, 2 or 4 files
+            # and sends a poll notification if a poll handle is present.
             for (($i, $t) = (0, $idx); $i < $nr; $i++,
                     $t = (($t + int(FSEL_FILES / $nr)) % FSEL_FILES)) {
                 next if $fsel_cnt[$t] == FSEL_CNT_MAX;
@@ -164,13 +161,14 @@ sub fsel_producer {
                     my $ph = $fsel_poll_handle[$t];
                     notify_poll($ph);
                     pollhandle_destroy($ph);
-                    $fsel_poll_handle[$t] = undef;
                     $fsel_poll_notify_mask &= ~(1 << $t);
+                    $fsel_poll_handle[$t] = undef;
                 }
             }
 
             $idx = ($idx + 1) % FSEL_FILES;
             if ($idx == 0) {
+                # Cycle through 1, 2 and 4.
                 $nr = ($nr * 2) % 7;
             }
         }
@@ -182,7 +180,6 @@ sub fsel_producer {
 croak("Fuse doesn't have poll") unless Fuse::fuse_version() >= 2.8;
 
 my %fuseargs = (
-    'mountpoint' => $ARGV[0],
     'getattr'   => 'main::fsel_getattr',
     'readdir'   => 'main::fsel_readdir',
     'open'      => 'main::fsel_open',
@@ -201,6 +198,8 @@ GetOptions(
     }
 ) || croak("Malformed options passed");
 
+$fuseargs{'mountpoint'} = $ARGV[0];
+
 my $thread = threads->create(\&fsel_producer);
 
 Fuse::main(%fuseargs);