-
Notifications
You must be signed in to change notification settings - Fork 4
FireFUSE Notes
This page is really just a collection of notes on the internals of FUSE and FireFUSE, that I started for my own purposes, that others may one day find useful.
- FUSE homepage http://fuse.sourceforge.net/
- API Reference http://fuse.sourceforge.net/doxygen/index.html
- http://www.cs.hmc.edu/~geoff/classes/hmc.cs135.201001/homework/fuse/fuse_doc.html
- doxygen: fuse_file_info struct: http://fuse.sourceforge.net/doxygen/structfuse__file__info.html
- Good FUSE examples: SSHFS (C with few comments), YoutubeFS (python), dedupfs, GlusterFS
-
ps -ef | grep nodeshow all node.js processes -
ps -ef | grep raspistillshow all raspistill processes sudo fusermount -u /dev/firefuse-
sudo lsof /dev/firefusewill show you any programs that are currently have files open in FIREFUSE. Use this if you get a "Device or resource busy" error when trying to run thefusermount -u /dev/firefuseabove. NOTE: You may have to install this, as it doesn't come stock with Debian.sudo apt-get install lsofshould install it. sudo kill -9 pid-of-raspistill-
sudo nano /var/log/firefuse.logOpen log start figuring out what went wrong ls -l /dev/firefuse-
rm version-xxxwhere xxx is whatever 'version' files show up in the FireREST directory. This will causefire/upgradeto rebuild EVERYTHING, which will take a while. -
fire/web -sLaunch FireREST webserver in background for current user -
fire/web -rRestart FireREST webserver -
fire/web -kKill FireREST webserver -
fire/log -cContinuously copy log entries to console (CTRL-C to quit) -
fire/log -tLog at TRACE level and show fully detailed information about FireFUSE activity -
fire/log -dLog at DEBUG level and show some detailed information about FireFUSE activity -
fire/log -iLog at INFO level (default): -
fire/config -dApply default configuration file -
fire/config -D myconfig.jsonSet default configuration file -
fire/config -e examples/400x400.jsonEdit current configuration file to use 400x400 camera -
fire/config custom/myconfig.jsonApply custom configuration file -
fire/upgradewill upgrade to you the latest and greatest FireFUSE, FireREST, and FireSight versions.
- ENOSYS: Function not implemented errno.EROFS: Read-only file system
- EPERM: Operation not permitted
- EACCES: Permission denied
- ENOENT: No such file or directory
- EIO:** I/O error
- EEXIST: File exists
- ENOTDIR: Not a directory
- EISDIR: Is a directory
- ENOTEMPTY: Directory not empty
- ESRCH: No process or process group can be found corresponding to that specified by pid.
- EINVAL: The value of the sig argument is an invalid or unsupported signal number.
/dev/firefuse/config.json/dev/firefuse/echo/dev/firefuse/firelog/dev/firefuse/firestep/dev/firefuse/holes/dev/firefuse/status-
/var/firefuse/config.jsonis the main config file for FireFUSE, FireREST, etc.. -
/var/firefuse/raspistill.PIDcontains the process ID of Raspistill, which runs in the background -
/var/log/firefuse.logis the debug log for firefuse (see section below for details).
- When building, make sure to stop node.js and close any Samba windows on client PCs. These will cause the build to fail, as it needs to unmount the fuse system.
FireFUSE will log debug info to:
/var/log/firefuse.log
You can change the FireFUSE debug level when building it. If you look at loginfo commands, if you want more info in debugging, change the debug level to a higher level. At level 0, only errors get logged. At level 4, everything gets logged. Lines w/'i' after timestamp: the letter 'i' is the level of the logging
Excerpted from: https://github.com/firepick1/FireSight/blob/master/FireLog.h
#define FIRELOG_ERROR 0
#define FIRELOG_WARN 1
#define FIRELOG_INFO 2
#define FIRELOG_DEBUG 3
#define FIRELOG_TRACE 4
ok. here's what's going on. there are multiple threads running at the same time.
background thread and foreground thread
the foreground handles FUSE file access
this means that if the foreground thread blocks on ANYTHING, the whole FUSE freezes
for GCODE stuff, the foreground puts the GCODE into a queue for the background thread to send on to Marlin.
That way the background thread can block on Marlin while the foreground thread serves FUSE requests
with raspistill being another process, there's even more things going on
you saw the signal, but the return is not immediate (FireFUSE sends the KILL signal to raspistill. Then raspistill does something indeterminate but FireFUSE has moved on after having sent the signal and no longer cares)
what happens is that raspistill writes to a file
amusingly, that file is...in FireFUSE
you'll see that in cv.cpp
raspistill opens the file, which means that FireFUSE cve_open gets called
then cve_write several times
then cve_release
so now there are two things happening:
- the triggering request to camera.jpg is STILL waiting
- FireFUSE has to simultaneously accept raspistill's data write to the shared queue.
it's very non-sequential and multi-threaded, which is a PIA
once #2 is complete, #1 can unblock and return the queued image to the end user
oh. the one difference between sync and non-sync is the FireFUSE queue
the FireFUSE queue on a non-sync call will always succeed immediately because it just returns the latest thing in the queue.
that is VERY fast and satisfies most clients EXCEPT for folks who need the real latest image.
Sync has to wait for the queue to refresh after raspistill has written the file
queues know if they have fresh or stale data.
so all sync has to do is pthread_yield() until the image is fresh.
then there might be a bug in FireFUSE where it is not yielding until fresh
so sync is basically implemented by clearing the queues of all fresh data and sending KILL to raspistill. That way, the next image in will be taken as the fresh one. By fresh I don't mean latest. By fresh I mean "nobody looked at it yet". It could be fresh and a week old if nobody looked at it. Basically we clean the shelf of old stuff and wait for the new
NOTE: Queues are currently LIFOs.
There are multiple queues all over, at least the ones you mentioned, but others for all the various things running around the system. for example camera->monitor queue, etc.
it's a bit mind-bendy, yes. for example, monitor doesn't always show the camera, sometimes it shows firesight output. that's why it has it's own queue. and when you are writing to camera.jpg, it ALSO needs a queue because the write takes multiple write calls (you'll see that in the log). without a queue you get pieces of image and that's bad.
the smartptrs are in the queues but are not the queues. each q element is a smartptr
T peek ()-
T get ()This is called when a non-syncing file is read. -
T get_sync (int msTimeout=0)This is called when a file in /sync/ is read. void post (T value)bool isFresh ()-
long getWriteCount ()writeCount gets incremented every time that long getReadCount ()private: T values[2];-
private: syncCountIncremented every time get_sync() is called, and decremented every time post() is called.
NOTE: Semaphore gets posted if syncCount gets decremented by post().
Instances:
CVE: LIFOCache<SmartPointer<char> > src_saved_pngCVE: LIFOCache<SmartPointer<char> > src_save_fireCVE: LIFOCache<SmartPointer<char> > src_process_fireCVE: LIFOCache<SmartPointer<char> > src_firesight_jsonCVE: LIFOCache<SmartPointer<char> > src_properties_jsonCameraNode: LIFOCache<SmartPointer<char> > src_camera_jpgCameraNode: LIFOCache<Mat> src_camera_mat_grayCameraNode: LIFOCache<Mat> src_camera_mat_bgrCameraNode: LIFOCache<SmartPointer<char> > src_monitor_jpgCameraNode: LIFOCache<SmartPointer<char> > src_output_jpg
SmartPointer (T *aPtr, size_t count=0, int flags=ALLOCATE, size_t blockSize=1, char blockPad=0)SmartPointer (const SmartPointer &that)SmartPointer & operator= (SmartPointer that)T * data () constint getReferences ()T & operator* ()const T & operator* () constT * operator-> ()const T * operator-> () constoperator T * () constsize_t size () constvoid setSize (size_t value)size_t allocated_size () const