|
1
|
1 #pragma once
|
|
|
2
|
|
|
3 /*
|
|
|
4 File lock management API
|
|
|
5 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.
|
|
|
6 The semantics are similar to those of blocking POSIX flock().
|
|
|
7 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.
|
|
|
8 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.
|
|
|
9
|
|
|
10 Usage examples:
|
|
|
11 If you want to write tags to an audio file, using low level methods such as input or album_art_editor APIs-
|
|
|
12 Obtain a write lock before accessing your file and release it when done.
|
|
|
13 If you want to keep an audio file open for an extended period of time and allow others to write to it-
|
|
|
14 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.
|
|
|
15
|
|
|
16 Final note:
|
|
|
17 Majority of the fb2k components will never need this API.
|
|
|
18 If you carry out tag updates via metadb_io, the locking is already dealt with by fb2k core.
|
|
|
19 */
|
|
|
20
|
|
|
21 //! An instance of a file lock object. Use file_lock_manager to instantiate.
|
|
|
22 class NOVTABLE file_lock : public service_base {
|
|
|
23 public:
|
|
|
24 //! 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
|
|
|
25 //! Typically, time consuming read operations check this periodically and close the file / release the lock / reacquire the lock / reopen the file when signaled.
|
|
|
26 virtual bool is_release_requested() = 0;
|
|
|
27
|
|
|
28 FB2K_MAKE_SERVICE_INTERFACE(file_lock, service_base);
|
|
|
29 };
|
|
|
30
|
|
|
31 typedef service_ptr_t<file_lock> file_lock_ptr;
|
|
|
32
|
|
|
33 //! \since 1.5
|
|
|
34 //! Modern version of file locking. \n
|
|
|
35 //! A read lock can be interrupted by a write lock request, from the thread that requested writing. \n
|
|
|
36 class NOVTABLE file_lock_interrupt : public service_base {
|
|
|
37 FB2K_MAKE_SERVICE_INTERFACE(file_lock_interrupt, service_base);
|
|
|
38 public:
|
|
|
39 //! Please note that interrupt() is called outside any sync scopes and may be called after lock reference has been released. \n
|
|
|
40 //! It is implementer's responsibility to safeguard against such. \n
|
|
|
41 //! 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
|
|
|
42 //! 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
|
|
|
43 //! If the function was aborted, it may be called again on the same object. \n
|
|
|
44 //! If the function succeeded, it will not be called again on the same object; the object will be released immediately after.
|
|
|
45 virtual void interrupt( abort_callback & aborter ) = 0;
|
|
|
46
|
|
|
47 static file_lock_interrupt::ptr create( std::function< void (abort_callback&)> );
|
|
|
48 };
|
|
|
49
|
|
|
50 //! Entry point class for obtaining file_lock objects.
|
|
|
51 class NOVTABLE file_lock_manager : public service_base {
|
|
|
52 public:
|
|
|
53 enum t_mode {
|
|
|
54 mode_read = 0,
|
|
|
55 mode_write
|
|
|
56 };
|
|
|
57 //! Acquires a read or write lock for this file path. \n
|
|
|
58 //! If asked for read access, waits until nobody else holds a write lock for this path (but others may read at the same time).
|
|
|
59 //! If asked for write access, access until nobody else holds a read or write lock for this path. \n
|
|
|
60 //! The semantics are similar to those of blocking POSIX flock().
|
|
|
61 virtual file_lock_ptr acquire(const char * p_path, t_mode p_mode, abort_callback & p_abort) = 0;
|
|
|
62
|
|
|
63 //! Helper, calls acquire() with mode_read.
|
|
|
64 file_lock_ptr acquire_read(const char * p_path, abort_callback & p_abort) { return acquire(p_path, mode_read, p_abort); }
|
|
|
65 //! Helper, calls acquire() with mode_write.
|
|
|
66 file_lock_ptr acquire_write(const char * p_path, abort_callback & p_abort) { return acquire(p_path, mode_write, p_abort); }
|
|
|
67
|
|
|
68
|
|
|
69 FB2K_MAKE_SERVICE_COREAPI(file_lock_manager);
|
|
|
70 };
|
|
|
71
|
|
|
72 // \since 1.5
|
|
|
73 class NOVTABLE file_lock_manager_v2 : public file_lock_manager {
|
|
|
74 FB2K_MAKE_SERVICE_COREAPI_EXTENSION( file_lock_manager_v2, file_lock_manager );
|
|
|
75 public:
|
|
|
76 virtual fb2k::objRef acquire_read_v2(const char * p_path, file_lock_interrupt::ptr interruptHandler, abort_callback & p_abort) = 0;
|
|
|
77 };
|