2 * Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
3 * License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
5 #include "cmogstored.h"
7 static int notes
[MOG_NOTIFY_MAX
];
8 static struct mog_fd
*notify_mfd
;
9 static time_t usage_file_updated_at
;
10 static time_t usage_file_interval
= 10;
11 struct mog_queue
*mog_notify_queue
;
13 void mog_notify_init(void)
15 const char *interval
= getenv("MOG_DISK_USAGE_INTERVAL");
18 int i
= atoi(interval
);
21 usage_file_interval
= (time_t)i
;
24 assert(mog_notify_queue
== NULL
&& "notify queue already initialized");
25 assert(notify_mfd
== NULL
&& "notify_mfd already initialized");
27 mog_notify_queue
= mog_queue_new();
28 notify_mfd
= mog_selfwake_new();
30 struct mog_selfwake
*notify
= ¬ify_mfd
->as
.selfwake
;
31 assert(notify
->writer
&& "notify writer not initialized");
32 notify
->queue
= mog_notify_queue
;
33 mog_idleq_add(notify
->queue
, notify_mfd
, MOG_QEV_RD
);
37 static void global_mkusage(void)
40 usage_file_updated_at
= time(NULL
);
43 static inline bool note_xchg(enum mog_notification note
, int from
, int to
)
45 return __sync_bool_compare_and_swap(¬es
[note
], from
, to
);
48 static void note_run(void)
50 if (note_xchg(MOG_NOTIFY_DEVICE_REFRESH
, 1, 0))
53 if (note_xchg(MOG_NOTIFY_AIO_THREADS
, 1, 0))
54 mog_svc_aio_threads_handler();
57 /* drain the pipe and process notifications */
58 static void note_queue_step(struct mog_fd
*mfd
)
60 mog_selfwake_drain(mfd
);
62 mog_idleq_push(mfd
->as
.selfwake
.queue
, mfd
, MOG_QEV_RD
);
65 static void notify_queue_step(struct mog_fd
*mfd
)
67 switch (mfd
->fd_type
) {
68 case MOG_FD_TYPE_SELFWAKE
: note_queue_step(mfd
); return;
69 case MOG_FD_TYPE_IOSTAT
: mog_iostat_queue_step(mfd
); return;
71 assert(0 && mfd
->fd_type
&& "bad fd_type in queue");
75 /* this is the main loop of cmogstored */
76 void mog_notify_wait(bool need_usage_file
)
78 time_t next
= usage_file_updated_at
+ usage_file_interval
;
79 time_t now
= time(NULL
);
80 time_t timeout
= next
- now
;
87 * epoll_wait() with timeout==0 can avoid some slow paths,
88 * so take anything that's already ready before sleeping
90 while ((mfd
= mog_idleq_wait(mog_notify_queue
, 0)))
91 notify_queue_step(mfd
);
93 if (need_usage_file
== false)
100 mfd
= mog_idleq_wait_intr(mog_notify_queue
, timeout
);
102 notify_queue_step(mfd
);
105 * errno == EINTR, but epoll_pwait on some Linux v5.0+/v5.1+
106 * fails to return EINTR. This should be fixed in Linux,
108 * <20190427093319.sgicqik2oqkez3wk@dcvr>
109 * <20190507043954.9020-1-deepa.kernel@gmail.com>
114 /* this is async-signal safe */
115 void mog_notify(enum mog_notification note
)
118 case MOG_NOTIFY_DEVICE_REFRESH
:
119 case MOG_NOTIFY_AIO_THREADS
:
120 note_xchg(note
, 0, 1);
121 mog_selfwake_interrupt();
123 case MOG_NOTIFY_SIGNAL
: break;
124 default: assert(0 && "bad note passed");
126 mog_selfwake_trigger(notify_mfd
);