78 lines
4.4 KiB
C++
78 lines
4.4 KiB
C++
#pragma once
|
|
|
|
/*
|
|
File lock management API
|
|
Historical note: while this API was first published in a 2018 release of the SDK, it had been around for at least a decade and is supported in all fb2k versions from 0.9 up.
|
|
The semantics are similar to those of blocking POSIX flock().
|
|
Since read locks are expected to be held for a long period of time - for an example, when playing an audio track, a holder of such lock can query whether someone else is waiting for this lock to be released.
|
|
Various audio file operations performed by fb2k core use file locks to synchronize access to the files - in particular, to allow graceful updates of tags on the currently playing track.
|
|
|
|
Usage examples:
|
|
If you want to write tags to an audio file, using low level methods such as input or album_art_editor APIs-
|
|
Obtain a write lock before accessing your file and release it when done.
|
|
If you want to keep an audio file open for an extended period of time and allow others to write to it-
|
|
Obtain a read lock, check is_release_requested() on it periodically; when it returns true, close the file, release the lock, obtain a new lock (which will block you until the peding write operation has completed), reopen the file and resume decoding where you left.
|
|
|
|
Final note:
|
|
Majority of the fb2k components will never need this API.
|
|
If you carry out tag updates via metadb_io, the locking is already dealt with by fb2k core.
|
|
*/
|
|
|
|
//! An instance of a file lock object. Use file_lock_manager to instantiate.
|
|
class NOVTABLE file_lock : public service_base {
|
|
public:
|
|
//! Returns whether we're blocking other attempts to access this file. A read lock does not block other read locks, but a write lock requires exclusive access.\n
|
|
//! Typically, time consuming read operations check this periodically and close the file / release the lock / reacquire the lock / reopen the file when signaled.
|
|
virtual bool is_release_requested() = 0;
|
|
|
|
FB2K_MAKE_SERVICE_INTERFACE(file_lock, service_base);
|
|
};
|
|
|
|
typedef service_ptr_t<file_lock> file_lock_ptr;
|
|
|
|
//! \since 1.5
|
|
//! Modern version of file locking. \n
|
|
//! A read lock can be interrupted by a write lock request, from the thread that requested writing. \n
|
|
class NOVTABLE file_lock_interrupt : public service_base {
|
|
FB2K_MAKE_SERVICE_INTERFACE(file_lock_interrupt, service_base);
|
|
public:
|
|
//! Please note that interrupt() is called outside any sync scopes and may be called after lock reference has been released. \n
|
|
//! It is implementer's responsibility to safeguard against such. \n
|
|
//! The interrupt() function must *never* fail, unless aborted by calling context - which means that whoever asked for write access is aborting whatever they're doing. \n
|
|
//! This function may block for as long as it takes to release the owned resources, but must be able to abort cleanly if doing so. \n
|
|
//! If the function was aborted, it may be called again on the same object. \n
|
|
//! If the function succeeded, it will not be called again on the same object; the object will be released immediately after.
|
|
virtual void interrupt( abort_callback & aborter ) = 0;
|
|
|
|
static file_lock_interrupt::ptr create( std::function< void (abort_callback&)> );
|
|
};
|
|
|
|
//! Entry point class for obtaining file_lock objects.
|
|
class NOVTABLE file_lock_manager : public service_base {
|
|
public:
|
|
enum t_mode {
|
|
mode_read = 0,
|
|
mode_write
|
|
};
|
|
//! Acquires a read or write lock for this file path. \n
|
|
//! If asked for read access, waits until nobody else holds a write lock for this path (but others may read at the same time).
|
|
//! If asked for write access, access until nobody else holds a read or write lock for this path. \n
|
|
//! The semantics are similar to those of blocking POSIX flock().
|
|
virtual file_lock_ptr acquire(const char * p_path, t_mode p_mode, abort_callback & p_abort) = 0;
|
|
|
|
//! Helper, calls acquire() with mode_read.
|
|
file_lock_ptr acquire_read(const char * p_path, abort_callback & p_abort) { return acquire(p_path, mode_read, p_abort); }
|
|
//! Helper, calls acquire() with mode_write.
|
|
file_lock_ptr acquire_write(const char * p_path, abort_callback & p_abort) { return acquire(p_path, mode_write, p_abort); }
|
|
|
|
|
|
FB2K_MAKE_SERVICE_COREAPI(file_lock_manager);
|
|
};
|
|
|
|
// \since 1.5
|
|
class NOVTABLE file_lock_manager_v2 : public file_lock_manager {
|
|
FB2K_MAKE_SERVICE_COREAPI_EXTENSION( file_lock_manager_v2, file_lock_manager );
|
|
public:
|
|
virtual fb2k::objRef acquire_read_v2(const char * p_path, file_lock_interrupt::ptr interruptHandler, abort_callback & p_abort) = 0;
|
|
};
|