|
1
|
1 #pragma once
|
|
|
2
|
|
|
3 namespace foobar2000_io {
|
|
|
4
|
|
|
5 PFC_DECLARE_EXCEPTION(exception_aborted,pfc::exception,"User abort");
|
|
|
6
|
|
|
7 typedef pfc::eventHandle_t abort_callback_event;
|
|
|
8
|
|
|
9 #ifdef check
|
|
|
10 #undef check
|
|
|
11 #endif
|
|
|
12 //! This class is used to signal underlying worker code whether user has decided to abort a potentially time-consuming operation. \n
|
|
|
13 //! It is commonly required by all filesystem related or decoding-related operations. \n
|
|
|
14 //! Code that receives an abort_callback object should periodically check it and abort any operations being performed if it is signaled, typically throwing exception_aborted. \n
|
|
|
15 //! See abort_callback_impl for an implementation.
|
|
|
16 class NOVTABLE abort_callback
|
|
|
17 {
|
|
|
18 public:
|
|
|
19 //! Returns whether user has requested the operation to be aborted.
|
|
|
20 virtual bool is_aborting() const = 0;
|
|
|
21
|
|
|
22 inline bool is_set() const {return is_aborting();}
|
|
|
23
|
|
|
24 //! Retrieves event object that can be used with some OS calls. The even object becomes signaled when abort is triggered. On win32, this is equivalent to win32 event handle (see: CreateEvent). \n
|
|
|
25 //! You must not close this handle or call any methods that change this handle's state (SetEvent() or ResetEvent()), you can only wait for it.
|
|
|
26 virtual abort_callback_event get_abort_event() const = 0;
|
|
|
27
|
|
|
28 inline abort_callback_event get_handle() const {return get_abort_event();}
|
|
|
29
|
|
|
30 //! Checks if user has requested the operation to be aborted, and throws exception_aborted if so.
|
|
|
31 void check() const;
|
|
|
32
|
|
|
33 //! For compatibility with old code. Do not call.
|
|
|
34 inline void check_e() const {check();}
|
|
|
35
|
|
|
36
|
|
|
37 //! Sleeps p_timeout_seconds or less when aborted, throws exception_aborted on abort.
|
|
|
38 void sleep(double p_timeout_seconds) const;
|
|
|
39 //! Sleeps p_timeout_seconds or less when aborted, returns true when execution should continue, false when not.
|
|
|
40 bool sleep_ex(double p_timeout_seconds) const;
|
|
|
41 bool sleepNoThrow(double p_timeout_seconds) const { return sleep_ex(p_timeout_seconds); }
|
|
|
42
|
|
|
43 //! Waits for an event. Returns true if event is now signaled, false if the specified period has elapsed and the event did not become signaled. \n
|
|
|
44 //! Throws exception_aborted if aborted.
|
|
|
45 bool waitForEvent( pfc::eventHandle_t evtHandle, double timeOut ) const;
|
|
|
46 //! Waits for an event. Returns true if event is now signaled, false if the specified period has elapsed and the event did not become signaled. \n
|
|
|
47 //! Throws exception_aborted if aborted.
|
|
|
48 bool waitForEvent(pfc::event& evt, double timeOut) const;
|
|
|
49
|
|
|
50 //! Waits for an event. Returns once the event became signaled; throw exception_aborted if abort occurred first.
|
|
|
51 void waitForEvent(pfc::eventHandle_t evtHandle) const;
|
|
|
52 //! Waits for an event. Returns once the event became signaled; throw exception_aborted if abort occurred first.
|
|
|
53 void waitForEvent(pfc::event& evt) const;
|
|
|
54
|
|
|
55 bool waitForEventNoThrow(pfc::eventHandle_t evt) const;
|
|
|
56 bool waitForEventNoThrow(pfc::event& evt) const;
|
|
|
57
|
|
|
58 abort_callback( const abort_callback & ) = delete;
|
|
|
59 void operator=( const abort_callback & ) = delete;
|
|
|
60 protected:
|
|
|
61 abort_callback() {}
|
|
|
62 ~abort_callback() {}
|
|
|
63 };
|
|
|
64
|
|
|
65
|
|
|
66
|
|
|
67 //! Standard implementation of abort_callback interface.
|
|
|
68 class abort_callback_impl : public abort_callback {
|
|
|
69 public:
|
|
|
70 abort_callback_impl() {}
|
|
|
71 inline void abort() {set_state(true);}
|
|
|
72 inline void set() {set_state(true);}
|
|
|
73 inline void reset() {set_state(false);}
|
|
|
74
|
|
|
75 void set_state(bool p_state) {m_aborting = p_state; m_event.set_state(p_state);}
|
|
|
76
|
|
|
77 bool is_aborting() const override {return m_aborting;}
|
|
|
78
|
|
|
79 abort_callback_event get_abort_event() const override {return m_event.get_handle();}
|
|
|
80
|
|
|
81 private:
|
|
|
82 abort_callback_impl(const abort_callback_impl &) = delete;
|
|
|
83 const abort_callback_impl & operator=(const abort_callback_impl&) = delete;
|
|
|
84
|
|
|
85 volatile bool m_aborting = false;
|
|
|
86 pfc::event m_event;
|
|
|
87 };
|
|
|
88
|
|
|
89 //! Alternate abort_callback implementation, supply your own event handle to signal abort. \n
|
|
|
90 //! Slightly less efficient (is_aborting() polls the event instead of reading a bool variable).
|
|
|
91 class abort_callback_usehandle : public abort_callback {
|
|
|
92 public:
|
|
|
93 abort_callback_usehandle( abort_callback_event handle ) : m_handle(handle) {}
|
|
|
94
|
|
|
95 bool is_aborting() const override;
|
|
|
96 abort_callback_event get_abort_event() const override { return m_handle; }
|
|
|
97 protected:
|
|
|
98 const abort_callback_event m_handle;
|
|
|
99 };
|
|
|
100
|
|
|
101 class abort_callback_clone : public abort_callback_usehandle {
|
|
|
102 public:
|
|
|
103 abort_callback_clone(abort_callback_event handle) : abort_callback_usehandle(clone(handle)) {}
|
|
|
104 abort_callback_clone(abort_callback & arg) : abort_callback_usehandle(clone(arg.get_handle())) {}
|
|
|
105 ~abort_callback_clone() { close(m_handle); }
|
|
|
106
|
|
|
107 static abort_callback_event clone(abort_callback_event);
|
|
|
108 static void close(abort_callback_event);
|
|
|
109 };
|
|
|
110
|
|
|
111 //! Dummy abort_callback that never gets aborted. \n
|
|
|
112 //! Note that there's no need to create instances of it, use shared fb2k::noAbort object instead.
|
|
|
113 class abort_callback_dummy : public abort_callback {
|
|
|
114 public:
|
|
|
115 bool is_aborting() const override { return false; }
|
|
|
116
|
|
|
117 abort_callback_event get_abort_event() const override { return m_event;}
|
|
|
118 private:
|
|
|
119 const abort_callback_event m_event = GetInfiniteWaitEvent();
|
|
|
120 };
|
|
|
121
|
|
|
122 }
|
|
|
123 typedef foobar2000_io::abort_callback_event fb2k_event_handle;
|
|
|
124 typedef foobar2000_io::abort_callback fb2k_event;
|
|
|
125 typedef foobar2000_io::abort_callback_impl fb2k_event_impl;
|
|
|
126
|
|
|
127 using namespace foobar2000_io;
|
|
|
128
|
|
|
129 #define FB2K_PFCv2_ABORTER_SCOPE( abortObj ) \
|
|
|
130 (abortObj).check(); \
|
|
|
131 PP::waitableReadRef_t aborterRef = {(abortObj).get_abort_event()}; \
|
|
|
132 PP::aborter aborter_pfcv2( aborterRef ); \
|
|
|
133 PP::aborterScope l_aborterScope( aborter_pfcv2 );
|
|
|
134
|
|
|
135
|
|
|
136 namespace fb2k {
|
|
|
137 //! A shared abort_callback_dummy instance. \n
|
|
|
138 //! Use when some function requires an abort_callback& and you don't have one: somefunc(fb2k::noAbort);
|
|
|
139 extern abort_callback_dummy noAbort;
|
|
|
140 }
|