annotate foosdk/sdk/foobar2000/SDK/file_lock_manager.h @ 1:20d02a178406 default tip

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