#include "dinit-log.h"
#include "cpbuffer.h"
+// TODO should disarm, not remove, the file descriptor watchers when they are not busy
+// (and likewise re-arm instead of re-add them when new data arrives).
+
extern EventLoop_t eventLoop;
LogLevel log_level = LogLevel::WARN;
static ServiceSet *service_set = nullptr; // Reference to service set
-
-namespace {
- class BufferedLogStream;
-}
-
-// TODO just make this the callback, directly.
-static Rearm log_conn_callback(EventLoop_t *loop, BufferedLogStream *w, int revents) noexcept;
-
namespace {
class BufferedLogStream : public PosixFdWatcher<NullMutex>
{
- public:
- CPBuffer<4096> log_buffer;
-
+ private:
+
// Outgoing:
bool partway = false; // if we are partway throught output of a log message
bool discarded = false; // if we have discarded a message
- // Incoming:
- int current_index = 0; // current/next incoming message index
- // ^^ TODO is this always just the length of log_buffer?
-
// A "special message" is not stored in the circular buffer; instead
// it is delivered from an external buffer not managed by BufferedLogger.
bool special = false; // currently outputting special message?
char *special_buf; // buffer containing special message
int msg_index; // index into special message
+ public:
+ CPBuffer<4096> log_buffer;
+
+ // Incoming:
+ int current_index = 0; // current/next incoming message index
+ // ^^ TODO is this always just the length of log_buffer?
+
int fd;
void init(int fd)
{
- //ev_io_init(&eviocb, log_conn_callback, fd, EV_WRITE);
- //eviocb.data = this;
this->fd = fd;
}
- Rearm gotEvent(EventLoop_t *loop, int fd, int flags) noexcept override
- {
- return log_conn_callback(loop, this, flags);
- }
+ Rearm gotEvent(EventLoop_t *loop, int fd, int flags) noexcept override;
+
+ // Check whether the console can be released.
+ void flushForRelease();
};
}
static void release_console()
{
- //ev_io_stop(ev_default_loop(EVFLAG_AUTO), & log_stream[DLOG_CONS].eviocb);
- //log_stream[DLOG_CONS].deregisterWatch(&eventLoop); // now handled elsewhere
if (! log_to_console) {
int flags = fcntl(1, F_GETFL, 0);
fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
}
}
-static Rearm log_conn_callback(EventLoop_t * loop, BufferedLogStream * w, int revents) noexcept
+void BufferedLogStream::flushForRelease()
+{
+ // Try to flush any messages that are currently buffered. (Console is non-blocking
+ // so it will fail gracefully).
+ if (gotEvent(&eventLoop, fd, out_events) == Rearm::REMOVE) {
+ // Console has already been released at this point.
+ deregisterWatch(&eventLoop);
+ }
+ // gotEvent didn't want to disarm, so must be partway through a message; will
+ // release when it's finished.
+}
+
+Rearm BufferedLogStream::gotEvent(EventLoop_t *loop, int fd, int flags) noexcept
{
- auto &log_stream = *w;
+ // TODO correct for the case that this is *not* the console log stream.
+
+ auto &log_stream = *this;
- if (log_stream.special) {
+ if ((! partway) && log_stream.special) {
char * start = log_stream.special_buf + log_stream.msg_index;
char * end = std::find(log_stream.special_buf + log_stream.msg_index, (char *)nullptr, '\n');
- int r = write(w->fd, start, end - start + 1);
+ int r = write(fd, start, end - start + 1);
if (r >= 0) {
if (start + r > end) {
// All written: go on to next message in queue
log_stream.special = false;
log_stream.partway = false;
log_stream.msg_index = 0;
+
+ if (!log_to_console) {
+ release_console();
+ return Rearm::REMOVE;
+ }
}
else {
log_stream.msg_index += r;
len = eptr - ptr;
- int r = write(w->fd, ptr, len);
+ int r = write(fd, ptr, len);
if (r >= 0) {
bool complete = (r == len) && will_complete;
int flags = fcntl(1, F_GETFL, 0);
fcntl(1, F_SETFL, flags | O_NONBLOCK);
// Activate watcher:
- //ev_io_init(& log_stream[DLOG_CONS].eviocb, log_conn_callback, 1, EV_WRITE);
log_stream[DLOG_CONS].init(STDOUT_FILENO);
if (log_stream[DLOG_CONS].current_index > 0) {
- //ev_io_start(ev_default_loop(EVFLAG_AUTO), & log_stream[DLOG_CONS].eviocb);
log_stream[DLOG_CONS].registerWith(&eventLoop, log_stream[DLOG_CONS].fd, out_events);
}
log_to_console = true;
}
else if (! enable && log_to_console) {
log_to_console = false;
- if (! log_stream[DLOG_CONS].partway) {
- if (log_stream[DLOG_CONS].current_index > 0) {
- // Try to flush any messages that are currently buffered. (Console is non-blocking
- // so it will fail gracefully).
- log_conn_callback(&eventLoop, &log_stream[DLOG_CONS], out_events);
- }
- else {
- release_console();
- log_stream[DLOG_CONS].deregisterWatch(&eventLoop);
- }
- }
- // (if we're partway through logging a message, we release the console when
- // finished).
+ log_stream[DLOG_CONS].flushForRelease();
}
}