Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
f0d3b47a
Commit
f0d3b47a
authored
Jan 04, 2014
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
event/Loop: remove the GLib implementation
Now that the remaining known bugs in poll() implementation are fixed, we can go on without the GLib implementation.
parent
bfe75335
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
22 additions
and
722 deletions
+22
-722
configure.ac
configure.ac
+19
-58
DeferredMonitor.cxx
src/event/DeferredMonitor.cxx
+0
-35
DeferredMonitor.hxx
src/event/DeferredMonitor.hxx
+0
-23
IdleMonitor.cxx
src/event/IdleMonitor.cxx
+0
-29
IdleMonitor.hxx
src/event/IdleMonitor.hxx
+0
-28
Loop.cxx
src/event/Loop.cxx
+0
-48
Loop.hxx
src/event/Loop.hxx
+1
-61
MultiSocketMonitor.cxx
src/event/MultiSocketMonitor.cxx
+0
-101
MultiSocketMonitor.hxx
src/event/MultiSocketMonitor.hxx
+1
-108
SocketMonitor.cxx
src/event/SocketMonitor.cxx
+0
-97
SocketMonitor.hxx
src/event/SocketMonitor.hxx
+0
-69
TimeoutMonitor.cxx
src/event/TimeoutMonitor.cxx
+1
-36
TimeoutMonitor.hxx
src/event/TimeoutMonitor.hxx
+0
-29
No files found.
configure.ac
View file @
f0d3b47a
...
@@ -188,70 +188,38 @@ if test x$host_is_linux = xyes; then
...
@@ -188,70 +188,38 @@ if test x$host_is_linux = xyes; then
MPD_OPTIONAL_FUNC_NODEF(epoll, epoll_create1)
MPD_OPTIONAL_FUNC_NODEF(epoll, epoll_create1)
fi
fi
AC_ARG_WITH(eventloop,
AS_HELP_STRING(
[--with-eventloop=@<:@glib|internal|auto@:>@],
[specify event loop implementation (default=auto)]),,
[with_eventloop=auto])
AC_ARG_WITH(pollmethod,
AC_ARG_WITH(pollmethod,
AS_HELP_STRING(
AS_HELP_STRING(
[--with-pollmethod=@<:@epoll|poll|winselect|auto@:>@],
[--with-pollmethod=@<:@epoll|poll|winselect|auto@:>@],
[specify poll method for internal event loop (default=auto)]),,
[specify poll method for internal event loop (default=auto)]),,
[with_pollmethod=auto])
[with_pollmethod=auto])
if test "x$with_eventloop" = xauto; then
if test "x$with_pollmethod" = xauto; then
if
if test "x$enable_epoll" = xyes; then
test "x$enable_epoll" = xyes ||
with_pollmethod=epoll
test "x$host_is_windows" = xyes; then
elif test "x$enable_poll" = xyes; then
with_eventloop=internal
with_pollmethod=poll
elif test "x$host_is_windows" = xyes; then
with_pollmethod=winselect
else
else
with_eventloop=glib
AC_MSG_ERROR([no poll method is available for your platform])
fi
fi
fi
fi
case "$with_pollmethod" in
case "$with_eventloop" in
epoll)
glib)
AC_DEFINE(USE_EPOLL, 1, [Define to poll sockets with epoll])
AC_DEFINE(USE_GLIB_EVENTLOOP, 1,
[Define to use GLib event loop])
;;
;;
internal)
poll)
AC_DEFINE(USE_INTERNAL_EVENTLOOP, 1,
AC_DEFINE(USE_POLL, 1, [Define to poll sockets with poll])
[Define to use internal event loop])
;;
;;
*)
winselect)
AC_MSG_ERROR([unknown eventloop option: $with_eventloop])
AC_DEFINE(USE_WINSELECT, 1,
[Define to poll sockets with Windows select])
;;
;;
*)
AC_MSG_ERROR([unknown pollmethod option: $with_pollmethod])
esac
esac
if test "x$with_eventloop" = xinternal; then
if test "x$with_pollmethod" = xauto; then
if test "x$enable_epoll" = xyes; then
with_pollmethod=epoll
elif test "x$enable_poll" = xyes; then
with_pollmethod=poll
elif test "x$host_is_windows" = xyes; then
with_pollmethod=winselect
else
AC_MSG_ERROR([no poll method is available for your platform])
fi
fi
case "$with_pollmethod" in
epoll)
AC_DEFINE(USE_EPOLL, 1, [Define to poll sockets with epoll])
;;
poll)
AC_DEFINE(USE_POLL, 1, [Define to poll sockets with poll])
;;
winselect)
AC_DEFINE(USE_WINSELECT, 1,
[Define to poll sockets with Windows select])
;;
*)
AC_MSG_ERROR([unknown pollmethod option: $with_pollmethod])
esac
fi
dnl ---------------------------------------------------------------------------
dnl ---------------------------------------------------------------------------
dnl Allow tools to be specifically built
dnl Allow tools to be specifically built
dnl ---------------------------------------------------------------------------
dnl ---------------------------------------------------------------------------
...
@@ -1728,14 +1696,7 @@ printf '\n\t'
...
@@ -1728,14 +1696,7 @@ printf '\n\t'
results(mms,[MMS])
results(mms,[MMS])
printf '\nEvent loop:\n\t'
printf '\nEvent loop:\n\t'
case $with_eventloop in
printf $with_pollmethod
glib)
printf 'GLib'
;;
internal)
printf 'Internal (%s)' $with_pollmethod
;;
esac
printf '\n\n##########################################\n\n'
printf '\n\n##########################################\n\n'
...
...
src/event/DeferredMonitor.cxx
View file @
f0d3b47a
...
@@ -24,46 +24,11 @@
...
@@ -24,46 +24,11 @@
void
void
DeferredMonitor
::
Cancel
()
DeferredMonitor
::
Cancel
()
{
{
#ifdef USE_INTERNAL_EVENTLOOP
loop
.
RemoveDeferred
(
*
this
);
loop
.
RemoveDeferred
(
*
this
);
#endif
#ifdef USE_GLIB_EVENTLOOP
const
auto
id
=
source_id
.
exchange
(
0
);
if
(
id
!=
0
)
g_source_remove
(
id
);
#endif
}
}
void
void
DeferredMonitor
::
Schedule
()
DeferredMonitor
::
Schedule
()
{
{
#ifdef USE_INTERNAL_EVENTLOOP
loop
.
AddDeferred
(
*
this
);
loop
.
AddDeferred
(
*
this
);
#endif
#ifdef USE_GLIB_EVENTLOOP
const
unsigned
id
=
loop
.
AddIdle
(
Callback
,
this
);
const
auto
old_id
=
source_id
.
exchange
(
id
);
if
(
old_id
!=
0
)
g_source_remove
(
old_id
);
#endif
}
}
#ifdef USE_GLIB_EVENTLOOP
void
DeferredMonitor
::
Run
()
{
const
auto
id
=
source_id
.
exchange
(
0
);
if
(
id
!=
0
)
RunDeferred
();
}
gboolean
DeferredMonitor
::
Callback
(
gpointer
data
)
{
DeferredMonitor
&
monitor
=
*
(
DeferredMonitor
*
)
data
;
monitor
.
Run
();
return
false
;
}
#endif
src/event/DeferredMonitor.hxx
View file @
f0d3b47a
...
@@ -23,10 +23,6 @@
...
@@ -23,10 +23,6 @@
#include "check.h"
#include "check.h"
#include "Compiler.h"
#include "Compiler.h"
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h>
#endif
#include <atomic>
#include <atomic>
class
EventLoop
;
class
EventLoop
;
...
@@ -39,25 +35,12 @@ class EventLoop;
...
@@ -39,25 +35,12 @@ class EventLoop;
class
DeferredMonitor
{
class
DeferredMonitor
{
EventLoop
&
loop
;
EventLoop
&
loop
;
#ifdef USE_INTERNAL_EVENTLOOP
friend
class
EventLoop
;
friend
class
EventLoop
;
bool
pending
;
bool
pending
;
#endif
#ifdef USE_GLIB_EVENTLOOP
std
::
atomic
<
guint
>
source_id
;
#endif
public
:
public
:
#ifdef USE_INTERNAL_EVENTLOOP
DeferredMonitor
(
EventLoop
&
_loop
)
DeferredMonitor
(
EventLoop
&
_loop
)
:
loop
(
_loop
),
pending
(
false
)
{}
:
loop
(
_loop
),
pending
(
false
)
{}
#endif
#ifdef USE_GLIB_EVENTLOOP
DeferredMonitor
(
EventLoop
&
_loop
)
:
loop
(
_loop
),
source_id
(
0
)
{}
#endif
~
DeferredMonitor
()
{
~
DeferredMonitor
()
{
Cancel
();
Cancel
();
...
@@ -72,12 +55,6 @@ public:
...
@@ -72,12 +55,6 @@ public:
protected
:
protected
:
virtual
void
RunDeferred
()
=
0
;
virtual
void
RunDeferred
()
=
0
;
private
:
#ifdef USE_GLIB_EVENTLOOP
void
Run
();
static
gboolean
Callback
(
gpointer
data
);
#endif
};
};
#endif
/* MAIN_NOTIFY_H */
#endif
/* MAIN_NOTIFY_H */
src/event/IdleMonitor.cxx
View file @
f0d3b47a
...
@@ -31,14 +31,8 @@ IdleMonitor::Cancel()
...
@@ -31,14 +31,8 @@ IdleMonitor::Cancel()
if
(
!
IsActive
())
if
(
!
IsActive
())
return
;
return
;
#ifdef USE_INTERNAL_EVENTLOOP
active
=
false
;
active
=
false
;
loop
.
RemoveIdle
(
*
this
);
loop
.
RemoveIdle
(
*
this
);
#endif
#ifdef USE_GLIB_EVENTLOOP
g_source_remove
(
source_id
);
source_id
=
0
;
#endif
}
}
void
void
...
@@ -50,13 +44,8 @@ IdleMonitor::Schedule()
...
@@ -50,13 +44,8 @@ IdleMonitor::Schedule()
/* already scheduled */
/* already scheduled */
return
;
return
;
#ifdef USE_INTERNAL_EVENTLOOP
active
=
true
;
active
=
true
;
loop
.
AddIdle
(
*
this
);
loop
.
AddIdle
(
*
this
);
#endif
#ifdef USE_GLIB_EVENTLOOP
source_id
=
loop
.
AddIdle
(
Callback
,
this
);
#endif
}
}
void
void
...
@@ -64,26 +53,8 @@ IdleMonitor::Run()
...
@@ -64,26 +53,8 @@ IdleMonitor::Run()
{
{
assert
(
loop
.
IsInside
());
assert
(
loop
.
IsInside
());
#ifdef USE_INTERNAL_EVENTLOOP
assert
(
active
);
assert
(
active
);
active
=
false
;
active
=
false
;
#endif
#ifdef USE_GLIB_EVENTLOOP
assert
(
source_id
!=
0
);
source_id
=
0
;
#endif
OnIdle
();
OnIdle
();
}
}
#ifdef USE_GLIB_EVENTLOOP
gboolean
IdleMonitor
::
Callback
(
gpointer
data
)
{
IdleMonitor
&
monitor
=
*
(
IdleMonitor
*
)
data
;
monitor
.
Run
();
return
false
;
}
#endif
src/event/IdleMonitor.hxx
View file @
f0d3b47a
...
@@ -22,10 +22,6 @@
...
@@ -22,10 +22,6 @@
#include "check.h"
#include "check.h"
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h>
#endif
class
EventLoop
;
class
EventLoop
;
/**
/**
...
@@ -38,30 +34,15 @@ class EventLoop;
...
@@ -38,30 +34,15 @@ class EventLoop;
* as thread-safe.
* as thread-safe.
*/
*/
class
IdleMonitor
{
class
IdleMonitor
{
#ifdef USE_INTERNAL_EVENTLOOP
friend
class
EventLoop
;
friend
class
EventLoop
;
#endif
EventLoop
&
loop
;
EventLoop
&
loop
;
#ifdef USE_INTERNAL_EVENTLOOP
bool
active
;
bool
active
;
#endif
#ifdef USE_GLIB_EVENTLOOP
guint
source_id
;
#endif
public
:
public
:
#ifdef USE_INTERNAL_EVENTLOOP
IdleMonitor
(
EventLoop
&
_loop
)
IdleMonitor
(
EventLoop
&
_loop
)
:
loop
(
_loop
),
active
(
false
)
{}
:
loop
(
_loop
),
active
(
false
)
{}
#endif
#ifdef USE_GLIB_EVENTLOOP
IdleMonitor
(
EventLoop
&
_loop
)
:
loop
(
_loop
),
source_id
(
0
)
{}
#endif
~
IdleMonitor
()
{
~
IdleMonitor
()
{
Cancel
();
Cancel
();
...
@@ -72,13 +53,7 @@ public:
...
@@ -72,13 +53,7 @@ public:
}
}
bool
IsActive
()
const
{
bool
IsActive
()
const
{
#ifdef USE_INTERNAL_EVENTLOOP
return
active
;
return
active
;
#endif
#ifdef USE_GLIB_EVENTLOOP
return
source_id
!=
0
;
#endif
}
}
void
Schedule
();
void
Schedule
();
...
@@ -89,9 +64,6 @@ protected:
...
@@ -89,9 +64,6 @@ protected:
private
:
private
:
void
Run
();
void
Run
();
#ifdef USE_GLIB_EVENTLOOP
static
gboolean
Callback
(
gpointer
data
);
#endif
};
};
#endif
/* MAIN_NOTIFY_H */
#endif
/* MAIN_NOTIFY_H */
src/event/Loop.cxx
View file @
f0d3b47a
...
@@ -20,8 +20,6 @@
...
@@ -20,8 +20,6 @@
#include "config.h"
#include "config.h"
#include "Loop.hxx"
#include "Loop.hxx"
#ifdef USE_INTERNAL_EVENTLOOP
#include "system/Clock.hxx"
#include "system/Clock.hxx"
#include "TimeoutMonitor.hxx"
#include "TimeoutMonitor.hxx"
#include "SocketMonitor.hxx"
#include "SocketMonitor.hxx"
...
@@ -104,15 +102,12 @@ EventLoop::CancelTimer(TimeoutMonitor &t)
...
@@ -104,15 +102,12 @@ EventLoop::CancelTimer(TimeoutMonitor &t)
}
}
}
}
#endif
void
void
EventLoop
::
Run
()
EventLoop
::
Run
()
{
{
assert
(
thread
.
IsNull
());
assert
(
thread
.
IsNull
());
thread
=
ThreadId
::
GetCurrent
();
thread
=
ThreadId
::
GetCurrent
();
#ifdef USE_INTERNAL_EVENTLOOP
assert
(
!
quit
);
assert
(
!
quit
);
do
{
do
{
...
@@ -180,17 +175,10 @@ EventLoop::Run()
...
@@ -180,17 +175,10 @@ EventLoop::Run()
poll_result
.
Reset
();
poll_result
.
Reset
();
}
while
(
!
quit
);
}
while
(
!
quit
);
#endif
#ifdef USE_GLIB_EVENTLOOP
g_main_loop_run
(
loop
);
#endif
assert
(
thread
.
IsInside
());
assert
(
thread
.
IsInside
());
}
}
#ifdef USE_INTERNAL_EVENTLOOP
void
void
EventLoop
::
AddDeferred
(
DeferredMonitor
&
d
)
EventLoop
::
AddDeferred
(
DeferredMonitor
&
d
)
{
{
...
@@ -254,39 +242,3 @@ EventLoop::OnSocketReady(gcc_unused unsigned flags)
...
@@ -254,39 +242,3 @@ EventLoop::OnSocketReady(gcc_unused unsigned flags)
return
true
;
return
true
;
}
}
#endif
#ifdef USE_GLIB_EVENTLOOP
guint
EventLoop
::
AddIdle
(
GSourceFunc
function
,
gpointer
data
)
{
GSource
*
source
=
g_idle_source_new
();
g_source_set_callback
(
source
,
function
,
data
,
nullptr
);
guint
id
=
g_source_attach
(
source
,
GetContext
());
g_source_unref
(
source
);
return
id
;
}
GSource
*
EventLoop
::
AddTimeout
(
guint
interval_ms
,
GSourceFunc
function
,
gpointer
data
)
{
GSource
*
source
=
g_timeout_source_new
(
interval_ms
);
g_source_set_callback
(
source
,
function
,
data
,
nullptr
);
g_source_attach
(
source
,
GetContext
());
return
source
;
}
GSource
*
EventLoop
::
AddTimeoutSeconds
(
guint
interval_s
,
GSourceFunc
function
,
gpointer
data
)
{
GSource
*
source
=
g_timeout_source_new_seconds
(
interval_s
);
g_source_set_callback
(
source
,
function
,
data
,
nullptr
);
g_source_attach
(
source
,
GetContext
());
return
source
;
}
#endif
src/event/Loop.hxx
View file @
f0d3b47a
...
@@ -24,7 +24,6 @@
...
@@ -24,7 +24,6 @@
#include "thread/Id.hxx"
#include "thread/Id.hxx"
#include "Compiler.h"
#include "Compiler.h"
#ifdef USE_INTERNAL_EVENTLOOP
#include "PollGroup.hxx"
#include "PollGroup.hxx"
#include "thread/Mutex.hxx"
#include "thread/Mutex.hxx"
#include "WakeFD.hxx"
#include "WakeFD.hxx"
...
@@ -32,18 +31,11 @@
...
@@ -32,18 +31,11 @@
#include <list>
#include <list>
#include <set>
#include <set>
#endif
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h>
#endif
#ifdef USE_INTERNAL_EVENTLOOP
class
TimeoutMonitor
;
class
TimeoutMonitor
;
class
IdleMonitor
;
class
IdleMonitor
;
class
DeferredMonitor
;
class
DeferredMonitor
;
class
SocketMonitor
;
class
SocketMonitor
;
#endif
#include <assert.h>
#include <assert.h>
...
@@ -56,12 +48,8 @@ class SocketMonitor;
...
@@ -56,12 +48,8 @@ class SocketMonitor;
*
*
* @see SocketMonitor, MultiSocketMonitor, TimeoutMonitor, IdleMonitor
* @see SocketMonitor, MultiSocketMonitor, TimeoutMonitor, IdleMonitor
*/
*/
class
EventLoop
final
class
EventLoop
final
:
SocketMonitor
#ifdef USE_INTERNAL_EVENTLOOP
:
private
SocketMonitor
#endif
{
{
#ifdef USE_INTERNAL_EVENTLOOP
struct
TimerRecord
{
struct
TimerRecord
{
/**
/**
* Projected monotonic_clock_ms() value when this
* Projected monotonic_clock_ms() value when this
...
@@ -98,12 +86,6 @@ class EventLoop final
...
@@ -98,12 +86,6 @@ class EventLoop final
PollGroup
poll_group
;
PollGroup
poll_group
;
PollResult
poll_result
;
PollResult
poll_result
;
#endif
#ifdef USE_GLIB_EVENTLOOP
GMainContext
*
context
;
GMainLoop
*
loop
;
#endif
/**
/**
* A reference to the thread that is currently inside Run().
* A reference to the thread that is currently inside Run().
...
@@ -111,7 +93,6 @@ class EventLoop final
...
@@ -111,7 +93,6 @@ class EventLoop final
ThreadId
thread
;
ThreadId
thread
;
public
:
public
:
#ifdef USE_INTERNAL_EVENTLOOP
struct
Default
{};
struct
Default
{};
EventLoop
(
Default
dummy
=
Default
());
EventLoop
(
Default
dummy
=
Default
());
...
@@ -179,47 +160,6 @@ private:
...
@@ -179,47 +160,6 @@ private:
virtual
bool
OnSocketReady
(
unsigned
flags
)
override
;
virtual
bool
OnSocketReady
(
unsigned
flags
)
override
;
public
:
public
:
#endif
#ifdef USE_GLIB_EVENTLOOP
EventLoop
()
:
context
(
g_main_context_new
()),
loop
(
g_main_loop_new
(
context
,
false
)),
thread
(
ThreadId
::
Null
())
{}
struct
Default
{};
EventLoop
(
gcc_unused
Default
_dummy
)
:
context
(
g_main_context_ref
(
g_main_context_default
())),
loop
(
g_main_loop_new
(
context
,
false
)),
thread
(
ThreadId
::
Null
())
{}
~
EventLoop
()
{
g_main_loop_unref
(
loop
);
g_main_context_unref
(
context
);
}
GMainContext
*
GetContext
()
{
return
context
;
}
void
WakeUp
()
{
g_main_context_wakeup
(
context
);
}
void
Break
()
{
g_main_loop_quit
(
loop
);
}
void
Run
();
guint
AddIdle
(
GSourceFunc
function
,
gpointer
data
);
GSource
*
AddTimeout
(
guint
interval_ms
,
GSourceFunc
function
,
gpointer
data
);
GSource
*
AddTimeoutSeconds
(
guint
interval_s
,
GSourceFunc
function
,
gpointer
data
);
#endif
/**
/**
* Are we currently running inside this EventLoop's thread?
* Are we currently running inside this EventLoop's thread?
...
...
src/event/MultiSocketMonitor.cxx
View file @
f0d3b47a
...
@@ -25,8 +25,6 @@
...
@@ -25,8 +25,6 @@
#include <assert.h>
#include <assert.h>
#ifdef USE_INTERNAL_EVENTLOOP
MultiSocketMonitor
::
MultiSocketMonitor
(
EventLoop
&
_loop
)
MultiSocketMonitor
::
MultiSocketMonitor
(
EventLoop
&
_loop
)
:
IdleMonitor
(
_loop
),
TimeoutMonitor
(
_loop
),
ready
(
false
)
{
:
IdleMonitor
(
_loop
),
TimeoutMonitor
(
_loop
),
ready
(
false
)
{
}
}
...
@@ -64,102 +62,3 @@ MultiSocketMonitor::OnIdle()
...
@@ -64,102 +62,3 @@ MultiSocketMonitor::OnIdle()
Prepare
();
Prepare
();
}
}
}
}
#endif
#ifdef USE_GLIB_EVENTLOOP
/**
* The vtable for our GSource implementation. Unfortunately, we
* cannot declare it "const", because g_source_new() takes a non-const
* pointer, for whatever reason.
*/
static
GSourceFuncs
multi_socket_monitor_source_funcs
=
{
MultiSocketMonitor
::
Prepare
,
MultiSocketMonitor
::
Check
,
MultiSocketMonitor
::
Dispatch
,
nullptr
,
nullptr
,
nullptr
,
};
MultiSocketMonitor
::
MultiSocketMonitor
(
EventLoop
&
_loop
)
:
loop
(
_loop
),
source
((
Source
*
)
g_source_new
(
&
multi_socket_monitor_source_funcs
,
sizeof
(
*
source
))),
absolute_timeout_us
(
-
1
)
{
source
->
monitor
=
this
;
g_source_attach
(
&
source
->
base
,
loop
.
GetContext
());
}
MultiSocketMonitor
::~
MultiSocketMonitor
()
{
g_source_destroy
(
&
source
->
base
);
g_source_unref
(
&
source
->
base
);
source
=
nullptr
;
}
bool
MultiSocketMonitor
::
Prepare
(
gint
*
timeout_r
)
{
int
timeout_ms
=
*
timeout_r
=
PrepareSockets
();
absolute_timeout_us
=
timeout_ms
<
0
?
uint64_t
(
-
1
)
:
GetTime
()
+
uint64_t
(
timeout_ms
)
*
1000
;
return
false
;
}
bool
MultiSocketMonitor
::
Check
()
const
{
if
(
GetTime
()
>=
absolute_timeout_us
)
return
true
;
for
(
const
auto
&
i
:
fds
)
if
(
i
.
GetReturnedEvents
()
!=
0
)
return
true
;
return
false
;
}
/*
* GSource methods
*
*/
gboolean
MultiSocketMonitor
::
Prepare
(
GSource
*
_source
,
gint
*
timeout_r
)
{
Source
&
source
=
*
(
Source
*
)
_source
;
MultiSocketMonitor
&
monitor
=
*
source
.
monitor
;
assert
(
_source
==
&
monitor
.
source
->
base
);
return
monitor
.
Prepare
(
timeout_r
);
}
gboolean
MultiSocketMonitor
::
Check
(
GSource
*
_source
)
{
const
Source
&
source
=
*
(
const
Source
*
)
_source
;
const
MultiSocketMonitor
&
monitor
=
*
source
.
monitor
;
assert
(
_source
==
&
monitor
.
source
->
base
);
return
monitor
.
Check
();
}
gboolean
MultiSocketMonitor
::
Dispatch
(
GSource
*
_source
,
gcc_unused
GSourceFunc
callback
,
gcc_unused
gpointer
user_data
)
{
Source
&
source
=
*
(
Source
*
)
_source
;
MultiSocketMonitor
&
monitor
=
*
source
.
monitor
;
assert
(
_source
==
&
monitor
.
source
->
base
);
monitor
.
Dispatch
();
return
true
;
}
#endif
src/event/MultiSocketMonitor.hxx
View file @
f0d3b47a
...
@@ -23,15 +23,9 @@
...
@@ -23,15 +23,9 @@
#include "check.h"
#include "check.h"
#include "Compiler.h"
#include "Compiler.h"
#ifdef USE_INTERNAL_EVENTLOOP
#include "IdleMonitor.hxx"
#include "IdleMonitor.hxx"
#include "TimeoutMonitor.hxx"
#include "TimeoutMonitor.hxx"
#include "SocketMonitor.hxx"
#include "SocketMonitor.hxx"
#endif
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h>
#endif
#include <forward_list>
#include <forward_list>
#include <iterator>
#include <iterator>
...
@@ -55,12 +49,8 @@ class EventLoop;
...
@@ -55,12 +49,8 @@ class EventLoop;
* In PrepareSockets(), use UpdateSocketList() and AddSocket().
* In PrepareSockets(), use UpdateSocketList() and AddSocket().
* DispatchSockets() will be called if at least one socket is ready.
* DispatchSockets() will be called if at least one socket is ready.
*/
*/
class
MultiSocketMonitor
class
MultiSocketMonitor
:
IdleMonitor
,
TimeoutMonitor
#ifdef USE_INTERNAL_EVENTLOOP
:
private
IdleMonitor
,
private
TimeoutMonitor
#endif
{
{
#ifdef USE_INTERNAL_EVENTLOOP
class
SingleFD
final
:
public
SocketMonitor
{
class
SingleFD
final
:
public
SocketMonitor
{
MultiSocketMonitor
&
multi
;
MultiSocketMonitor
&
multi
;
...
@@ -105,99 +95,28 @@ class MultiSocketMonitor
...
@@ -105,99 +95,28 @@ class MultiSocketMonitor
friend
class
SingleFD
;
friend
class
SingleFD
;
bool
ready
,
refresh
;
bool
ready
,
refresh
;
#endif
#ifdef USE_GLIB_EVENTLOOP
struct
Source
{
GSource
base
;
MultiSocketMonitor
*
monitor
;
};
struct
SingleFD
{
GPollFD
pfd
;
constexpr
SingleFD
(
gcc_unused
MultiSocketMonitor
&
m
,
int
fd
,
unsigned
events
)
:
pfd
{
fd
,
gushort
(
events
),
0
}
{}
constexpr
int
GetFD
()
const
{
return
pfd
.
fd
;
}
constexpr
unsigned
GetEvents
()
const
{
return
pfd
.
events
;
}
constexpr
unsigned
GetReturnedEvents
()
const
{
return
pfd
.
revents
;
}
void
SetEvents
(
unsigned
_events
)
{
pfd
.
events
=
_events
;
}
};
EventLoop
&
loop
;
Source
*
source
;
uint64_t
absolute_timeout_us
;
#endif
std
::
forward_list
<
SingleFD
>
fds
;
std
::
forward_list
<
SingleFD
>
fds
;
public
:
public
:
#ifdef USE_INTERNAL_EVENTLOOP
static
constexpr
unsigned
READ
=
SocketMonitor
::
READ
;
static
constexpr
unsigned
READ
=
SocketMonitor
::
READ
;
static
constexpr
unsigned
WRITE
=
SocketMonitor
::
WRITE
;
static
constexpr
unsigned
WRITE
=
SocketMonitor
::
WRITE
;
static
constexpr
unsigned
ERROR
=
SocketMonitor
::
ERROR
;
static
constexpr
unsigned
ERROR
=
SocketMonitor
::
ERROR
;
static
constexpr
unsigned
HANGUP
=
SocketMonitor
::
HANGUP
;
static
constexpr
unsigned
HANGUP
=
SocketMonitor
::
HANGUP
;
#endif
#ifdef USE_GLIB_EVENTLOOP
static
constexpr
unsigned
READ
=
G_IO_IN
;
static
constexpr
unsigned
WRITE
=
G_IO_OUT
;
static
constexpr
unsigned
ERROR
=
G_IO_ERR
;
static
constexpr
unsigned
HANGUP
=
G_IO_HUP
;
#endif
MultiSocketMonitor
(
EventLoop
&
_loop
);
MultiSocketMonitor
(
EventLoop
&
_loop
);
~
MultiSocketMonitor
();
~
MultiSocketMonitor
();
#ifdef USE_INTERNAL_EVENTLOOP
using
IdleMonitor
::
GetEventLoop
;
using
IdleMonitor
::
GetEventLoop
;
#endif
#ifdef USE_GLIB_EVENTLOOP
EventLoop
&
GetEventLoop
()
{
return
loop
;
}
#endif
public
:
public
:
#ifdef USE_GLIB_EVENTLOOP
gcc_pure
uint64_t
GetTime
()
const
{
return
g_source_get_time
(
&
source
->
base
);
}
#endif
void
InvalidateSockets
()
{
void
InvalidateSockets
()
{
#ifdef USE_INTERNAL_EVENTLOOP
refresh
=
true
;
refresh
=
true
;
IdleMonitor
::
Schedule
();
IdleMonitor
::
Schedule
();
#endif
#ifdef USE_GLIB_EVENTLOOP
/* no-op because GLib always calls the GSource's
"prepare" method before each poll() anyway */
#endif
}
}
void
AddSocket
(
int
fd
,
unsigned
events
)
{
void
AddSocket
(
int
fd
,
unsigned
events
)
{
fds
.
emplace_front
(
*
this
,
fd
,
events
);
fds
.
emplace_front
(
*
this
,
fd
,
events
);
#ifdef USE_GLIB_EVENTLOOP
g_source_add_poll
(
&
source
->
base
,
&
fds
.
front
().
pfd
);
#endif
}
}
template
<
typename
E
>
template
<
typename
E
>
...
@@ -212,13 +131,7 @@ public:
...
@@ -212,13 +131,7 @@ public:
i
->
SetEvents
(
events
);
i
->
SetEvents
(
events
);
prev
=
i
;
prev
=
i
;
}
else
{
}
else
{
#ifdef USE_INTERNAL_EVENTLOOP
i
->
Steal
();
i
->
Steal
();
#endif
#ifdef USE_GLIB_EVENTLOOP
g_source_remove_poll
(
&
source
->
base
,
&
i
->
pfd
);
#endif
fds
.
erase_after
(
prev
);
fds
.
erase_after
(
prev
);
}
}
}
}
...
@@ -231,7 +144,6 @@ protected:
...
@@ -231,7 +144,6 @@ protected:
virtual
int
PrepareSockets
()
=
0
;
virtual
int
PrepareSockets
()
=
0
;
virtual
void
DispatchSockets
()
=
0
;
virtual
void
DispatchSockets
()
=
0
;
#ifdef USE_INTERNAL_EVENTLOOP
private
:
private
:
void
SetReady
()
{
void
SetReady
()
{
ready
=
true
;
ready
=
true
;
...
@@ -246,25 +158,6 @@ private:
...
@@ -246,25 +158,6 @@ private:
}
}
virtual
void
OnIdle
()
final
;
virtual
void
OnIdle
()
final
;
#endif
#ifdef USE_GLIB_EVENTLOOP
public
:
/* GSource callbacks */
static
gboolean
Prepare
(
GSource
*
source
,
gint
*
timeout_r
);
static
gboolean
Check
(
GSource
*
source
);
static
gboolean
Dispatch
(
GSource
*
source
,
GSourceFunc
callback
,
gpointer
user_data
);
private
:
bool
Prepare
(
gint
*
timeout_r
);
bool
Check
()
const
;
void
Dispatch
()
{
DispatchSockets
();
}
#endif
};
};
#endif
#endif
src/event/SocketMonitor.cxx
View file @
f0d3b47a
...
@@ -31,8 +31,6 @@
...
@@ -31,8 +31,6 @@
#include <sys/socket.h>
#include <sys/socket.h>
#endif
#endif
#ifdef USE_INTERNAL_EVENTLOOP
void
void
SocketMonitor
::
Dispatch
(
unsigned
flags
)
SocketMonitor
::
Dispatch
(
unsigned
flags
)
{
{
...
@@ -42,68 +40,6 @@ SocketMonitor::Dispatch(unsigned flags)
...
@@ -42,68 +40,6 @@ SocketMonitor::Dispatch(unsigned flags)
Cancel
();
Cancel
();
}
}
#endif
#ifdef USE_GLIB_EVENTLOOP
/*
* GSource methods
*
*/
gboolean
SocketMonitor
::
Prepare
(
gcc_unused
GSource
*
source
,
gcc_unused
gint
*
timeout_r
)
{
return
false
;
}
gboolean
SocketMonitor
::
Check
(
GSource
*
_source
)
{
const
Source
&
source
=
*
(
const
Source
*
)
_source
;
const
SocketMonitor
&
monitor
=
*
source
.
monitor
;
assert
(
_source
==
&
monitor
.
source
->
base
);
return
monitor
.
Check
();
}
gboolean
SocketMonitor
::
Dispatch
(
GSource
*
_source
,
gcc_unused
GSourceFunc
callback
,
gcc_unused
gpointer
user_data
)
{
Source
&
source
=
*
(
Source
*
)
_source
;
SocketMonitor
&
monitor
=
*
source
.
monitor
;
assert
(
_source
==
&
monitor
.
source
->
base
);
monitor
.
Dispatch
();
return
true
;
}
/**
* The vtable for our GSource implementation. Unfortunately, we
* cannot declare it "const", because g_source_new() takes a non-const
* pointer, for whatever reason.
*/
static
GSourceFuncs
socket_monitor_source_funcs
=
{
SocketMonitor
::
Prepare
,
SocketMonitor
::
Check
,
SocketMonitor
::
Dispatch
,
nullptr
,
nullptr
,
nullptr
,
};
SocketMonitor
::
SocketMonitor
(
int
_fd
,
EventLoop
&
_loop
)
:
fd
(
-
1
),
loop
(
_loop
),
source
(
nullptr
)
{
assert
(
_fd
>=
0
);
Open
(
_fd
);
}
#endif
SocketMonitor
::~
SocketMonitor
()
SocketMonitor
::~
SocketMonitor
()
{
{
if
(
IsDefined
())
if
(
IsDefined
())
...
@@ -114,23 +50,9 @@ void
...
@@ -114,23 +50,9 @@ void
SocketMonitor
::
Open
(
int
_fd
)
SocketMonitor
::
Open
(
int
_fd
)
{
{
assert
(
fd
<
0
);
assert
(
fd
<
0
);
#ifdef USE_GLIB_EVENTLOOP
assert
(
source
==
nullptr
);
#endif
assert
(
_fd
>=
0
);
assert
(
_fd
>=
0
);
fd
=
_fd
;
fd
=
_fd
;
#ifdef USE_GLIB_EVENTLOOP
poll
=
{
fd
,
0
,
0
};
source
=
(
Source
*
)
g_source_new
(
&
socket_monitor_source_funcs
,
sizeof
(
*
source
));
source
->
monitor
=
this
;
g_source_attach
(
&
source
->
base
,
loop
.
GetContext
());
g_source_add_poll
(
&
source
->
base
,
&
poll
);
#endif
}
}
int
int
...
@@ -143,12 +65,6 @@ SocketMonitor::Steal()
...
@@ -143,12 +65,6 @@ SocketMonitor::Steal()
int
result
=
fd
;
int
result
=
fd
;
fd
=
-
1
;
fd
=
-
1
;
#ifdef USE_GLIB_EVENTLOOP
g_source_destroy
(
&
source
->
base
);
g_source_unref
(
&
source
->
base
);
source
=
nullptr
;
#endif
return
result
;
return
result
;
}
}
...
@@ -157,13 +73,9 @@ SocketMonitor::Abandon()
...
@@ -157,13 +73,9 @@ SocketMonitor::Abandon()
{
{
assert
(
IsDefined
());
assert
(
IsDefined
());
#ifdef USE_INTERNAL_EVENTLOOP
int
old_fd
=
fd
;
int
old_fd
=
fd
;
fd
=
-
1
;
fd
=
-
1
;
loop
.
Abandon
(
old_fd
,
*
this
);
loop
.
Abandon
(
old_fd
,
*
this
);
#else
Steal
();
#endif
}
}
void
void
...
@@ -180,7 +92,6 @@ SocketMonitor::Schedule(unsigned flags)
...
@@ -180,7 +92,6 @@ SocketMonitor::Schedule(unsigned flags)
if
(
flags
==
GetScheduledFlags
())
if
(
flags
==
GetScheduledFlags
())
return
;
return
;
#ifdef USE_INTERNAL_EVENTLOOP
if
(
scheduled_flags
==
0
)
if
(
scheduled_flags
==
0
)
loop
.
AddFD
(
fd
,
flags
,
*
this
);
loop
.
AddFD
(
fd
,
flags
,
*
this
);
else
if
(
flags
==
0
)
else
if
(
flags
==
0
)
...
@@ -189,14 +100,6 @@ SocketMonitor::Schedule(unsigned flags)
...
@@ -189,14 +100,6 @@ SocketMonitor::Schedule(unsigned flags)
loop
.
ModifyFD
(
fd
,
flags
,
*
this
);
loop
.
ModifyFD
(
fd
,
flags
,
*
this
);
scheduled_flags
=
flags
;
scheduled_flags
=
flags
;
#endif
#ifdef USE_GLIB_EVENTLOOP
poll
.
events
=
flags
;
poll
.
revents
&=
flags
;
loop
.
WakeUp
();
#endif
}
}
SocketMonitor
::
ssize_t
SocketMonitor
::
ssize_t
...
...
src/event/SocketMonitor.hxx
View file @
f0d3b47a
...
@@ -21,14 +21,7 @@
...
@@ -21,14 +21,7 @@
#define MPD_SOCKET_MONITOR_HXX
#define MPD_SOCKET_MONITOR_HXX
#include "check.h"
#include "check.h"
#ifdef USE_INTERNAL_EVENTLOOP
#include "PollGroup.hxx"
#include "PollGroup.hxx"
#endif
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h>
#endif
#include <type_traits>
#include <type_traits>
...
@@ -56,60 +49,27 @@ class EventLoop;
...
@@ -56,60 +49,27 @@ class EventLoop;
* as thread-safe.
* as thread-safe.
*/
*/
class
SocketMonitor
{
class
SocketMonitor
{
#ifdef USE_GLIB_EVENTLOOP
struct
Source
{
GSource
base
;
SocketMonitor
*
monitor
;
};
#endif
int
fd
;
int
fd
;
EventLoop
&
loop
;
EventLoop
&
loop
;
#ifdef USE_INTERNAL_EVENTLOOP
/**
/**
* A bit mask of events that is currently registered in the EventLoop.
* A bit mask of events that is currently registered in the EventLoop.
*/
*/
unsigned
scheduled_flags
;
unsigned
scheduled_flags
;
#endif
#ifdef USE_GLIB_EVENTLOOP
Source
*
source
;
GPollFD
poll
;
#endif
public
:
public
:
#ifdef USE_INTERNAL_EVENTLOOP
static
constexpr
unsigned
READ
=
PollGroup
::
READ
;
static
constexpr
unsigned
READ
=
PollGroup
::
READ
;
static
constexpr
unsigned
WRITE
=
PollGroup
::
WRITE
;
static
constexpr
unsigned
WRITE
=
PollGroup
::
WRITE
;
static
constexpr
unsigned
ERROR
=
PollGroup
::
ERROR
;
static
constexpr
unsigned
ERROR
=
PollGroup
::
ERROR
;
static
constexpr
unsigned
HANGUP
=
PollGroup
::
HANGUP
;
static
constexpr
unsigned
HANGUP
=
PollGroup
::
HANGUP
;
#endif
#ifdef USE_GLIB_EVENTLOOP
static
constexpr
unsigned
READ
=
G_IO_IN
;
static
constexpr
unsigned
WRITE
=
G_IO_OUT
;
static
constexpr
unsigned
ERROR
=
G_IO_ERR
;
static
constexpr
unsigned
HANGUP
=
G_IO_HUP
;
#endif
typedef
std
::
make_signed
<
size_t
>::
type
ssize_t
;
typedef
std
::
make_signed
<
size_t
>::
type
ssize_t
;
#ifdef USE_INTERNAL_EVENTLOOP
SocketMonitor
(
EventLoop
&
_loop
)
SocketMonitor
(
EventLoop
&
_loop
)
:
fd
(
-
1
),
loop
(
_loop
),
scheduled_flags
(
0
)
{}
:
fd
(
-
1
),
loop
(
_loop
),
scheduled_flags
(
0
)
{}
SocketMonitor
(
int
_fd
,
EventLoop
&
_loop
)
SocketMonitor
(
int
_fd
,
EventLoop
&
_loop
)
:
fd
(
_fd
),
loop
(
_loop
),
scheduled_flags
(
0
)
{}
:
fd
(
_fd
),
loop
(
_loop
),
scheduled_flags
(
0
)
{}
#endif
#ifdef USE_GLIB_EVENTLOOP
SocketMonitor
(
EventLoop
&
_loop
)
:
fd
(
-
1
),
loop
(
_loop
),
source
(
nullptr
)
{}
SocketMonitor
(
int
_fd
,
EventLoop
&
_loop
);
#endif
~
SocketMonitor
();
~
SocketMonitor
();
...
@@ -145,13 +105,7 @@ public:
...
@@ -145,13 +105,7 @@ public:
unsigned
GetScheduledFlags
()
const
{
unsigned
GetScheduledFlags
()
const
{
assert
(
IsDefined
());
assert
(
IsDefined
());
#ifdef USE_INTERNAL_EVENTLOOP
return
scheduled_flags
;
return
scheduled_flags
;
#endif
#ifdef USE_GLIB_EVENTLOOP
return
poll
.
events
;
#endif
}
}
void
Schedule
(
unsigned
flags
);
void
Schedule
(
unsigned
flags
);
...
@@ -186,30 +140,7 @@ protected:
...
@@ -186,30 +140,7 @@ protected:
virtual
bool
OnSocketReady
(
unsigned
flags
)
=
0
;
virtual
bool
OnSocketReady
(
unsigned
flags
)
=
0
;
public
:
public
:
#ifdef USE_INTERNAL_EVENTLOOP
void
Dispatch
(
unsigned
flags
);
void
Dispatch
(
unsigned
flags
);
#endif
#ifdef USE_GLIB_EVENTLOOP
/* GSource callbacks */
static
gboolean
Prepare
(
GSource
*
source
,
gint
*
timeout_r
);
static
gboolean
Check
(
GSource
*
source
);
static
gboolean
Dispatch
(
GSource
*
source
,
GSourceFunc
callback
,
gpointer
user_data
);
private
:
bool
Check
()
const
{
assert
(
IsDefined
());
return
(
poll
.
revents
&
poll
.
events
)
!=
0
;
}
void
Dispatch
()
{
assert
(
IsDefined
());
OnSocketReady
(
poll
.
revents
&
poll
.
events
);
}
#endif
};
};
#endif
#endif
src/event/TimeoutMonitor.cxx
View file @
f0d3b47a
...
@@ -25,32 +25,19 @@ void
...
@@ -25,32 +25,19 @@ void
TimeoutMonitor
::
Cancel
()
TimeoutMonitor
::
Cancel
()
{
{
if
(
IsActive
())
{
if
(
IsActive
())
{
#ifdef USE_INTERNAL_EVENTLOOP
active
=
false
;
active
=
false
;
loop
.
CancelTimer
(
*
this
);
loop
.
CancelTimer
(
*
this
);
#endif
#ifdef USE_GLIB_EVENTLOOP
g_source_destroy
(
source
);
g_source_unref
(
source
);
source
=
nullptr
;
#endif
}
}
}
}
void
void
TimeoutMonitor
::
Schedule
(
unsigned
ms
)
TimeoutMonitor
::
Schedule
(
unsigned
ms
)
{
{
Cancel
();
Cancel
();
#ifdef USE_INTERNAL_EVENTLOOP
active
=
true
;
active
=
true
;
loop
.
AddTimer
(
*
this
,
ms
);
loop
.
AddTimer
(
*
this
,
ms
);
#endif
#ifdef USE_GLIB_EVENTLOOP
source
=
loop
.
AddTimeout
(
ms
,
Callback
,
this
);
#endif
}
}
void
void
...
@@ -58,33 +45,11 @@ TimeoutMonitor::ScheduleSeconds(unsigned s)
...
@@ -58,33 +45,11 @@ TimeoutMonitor::ScheduleSeconds(unsigned s)
{
{
Cancel
();
Cancel
();
#ifdef USE_INTERNAL_EVENTLOOP
Schedule
(
s
*
1000u
);
Schedule
(
s
*
1000u
);
#endif
#ifdef USE_GLIB_EVENTLOOP
source
=
loop
.
AddTimeoutSeconds
(
s
,
Callback
,
this
);
#endif
}
}
void
void
TimeoutMonitor
::
Run
()
TimeoutMonitor
::
Run
()
{
{
#ifdef USE_GLIB_EVENTLOOP
Cancel
();
#endif
OnTimeout
();
OnTimeout
();
}
}
#ifdef USE_GLIB_EVENTLOOP
gboolean
TimeoutMonitor
::
Callback
(
gpointer
data
)
{
TimeoutMonitor
&
monitor
=
*
(
TimeoutMonitor
*
)
data
;
monitor
.
Run
();
return
false
;
}
#endif
src/event/TimeoutMonitor.hxx
View file @
f0d3b47a
...
@@ -22,10 +22,6 @@
...
@@ -22,10 +22,6 @@
#include "check.h"
#include "check.h"
#ifdef USE_GLIB_EVENTLOOP
#include <glib.h>
#endif
class
EventLoop
;
class
EventLoop
;
/**
/**
...
@@ -37,31 +33,16 @@ class EventLoop;
...
@@ -37,31 +33,16 @@ class EventLoop;
* as thread-safe.
* as thread-safe.
*/
*/
class
TimeoutMonitor
{
class
TimeoutMonitor
{
#ifdef USE_INTERNAL_EVENTLOOP
friend
class
EventLoop
;
friend
class
EventLoop
;
#endif
EventLoop
&
loop
;
EventLoop
&
loop
;
#ifdef USE_INTERNAL_EVENTLOOP
bool
active
;
bool
active
;
#endif
#ifdef USE_GLIB_EVENTLOOP
GSource
*
source
;
#endif
public
:
public
:
#ifdef USE_INTERNAL_EVENTLOOP
TimeoutMonitor
(
EventLoop
&
_loop
)
TimeoutMonitor
(
EventLoop
&
_loop
)
:
loop
(
_loop
),
active
(
false
)
{
:
loop
(
_loop
),
active
(
false
)
{
}
}
#endif
#ifdef USE_GLIB_EVENTLOOP
TimeoutMonitor
(
EventLoop
&
_loop
)
:
loop
(
_loop
),
source
(
nullptr
)
{}
#endif
~
TimeoutMonitor
()
{
~
TimeoutMonitor
()
{
Cancel
();
Cancel
();
...
@@ -72,13 +53,7 @@ public:
...
@@ -72,13 +53,7 @@ public:
}
}
bool
IsActive
()
const
{
bool
IsActive
()
const
{
#ifdef USE_INTERNAL_EVENTLOOP
return
active
;
return
active
;
#endif
#ifdef USE_GLIB_EVENTLOOP
return
source
!=
nullptr
;
#endif
}
}
void
Schedule
(
unsigned
ms
);
void
Schedule
(
unsigned
ms
);
...
@@ -90,10 +65,6 @@ protected:
...
@@ -90,10 +65,6 @@ protected:
private
:
private
:
void
Run
();
void
Run
();
#ifdef USE_GLIB_EVENTLOOP
static
gboolean
Callback
(
gpointer
data
);
#endif
};
};
#endif
/* MAIN_NOTIFY_H */
#endif
/* MAIN_NOTIFY_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment