*
*/
+#include "common/DoutStreambuf.h"
+#include "common/Mutex.h"
#include "common/code_environment.h"
#include "common/config.h"
-#include "common/DoutStreambuf.h"
#include "common/entity_name.h"
#include "common/errno.h"
-#include "common/Mutex.h"
#include "common/safe_io.h"
+#include "common/simple_spin.h"
#include <values.h>
#include <assert.h>
// TODO: get rid of this lock using thread-local storage
extern pthread_mutex_t _dout_lock;
+static simple_spinlock_t dout_emergency_lock = SIMPLE_SPINLOCK_INITIALIZER;
+
+/* Streams that we will write to in dout_emergency.
+ * Protected by dout_emergency_lock. */
+EmergencyLogger *dout_emerg_streams[] =
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+#define NUM_DOUT_EMERG_STREAMS \
+ (sizeof(dout_emerg_streams)/sizeof(dout_emerg_streams[0]))
+
+EmergencyLogger::~EmergencyLogger()
+{
+}
+
//////////////////////// Helper functions //////////////////////////
// Try a 0-byte write to a file descriptor to see if it open.
static bool fd_is_open(int fd)
// Initialize output_buffer
_clear_output_buffer();
+
+ simple_spin_lock(&dout_emergency_lock);
+ for (size_t i = 0; i < NUM_DOUT_EMERG_STREAMS; ++i) {
+ if (dout_emerg_streams[i] == 0) {
+ dout_emerg_streams[i] = this;
+ break;
+ }
+ }
+ simple_spin_unlock(&dout_emergency_lock);
}
template <typename charT, typename traits>
TEMP_FAILURE_RETRY(::close(ofd));
ofd = -1;
}
+ simple_spin_lock(&dout_emergency_lock);
+ for (size_t i = 0; i < NUM_DOUT_EMERG_STREAMS; ++i) {
+ if (dout_emerg_streams[i] == this) {
+ dout_emerg_streams[i] = 0;
+ break;
+ }
+ }
+ simple_spin_unlock(&dout_emergency_lock);
}
// This function is called when the output buffer is filled.
return oss.str();
}
+/* This function doesn't take the dout lock, so some interleaving or weirdness
+ * may happen if concurrent writes are going on. But this is for emergencies,
+ * so we don't care.
+ */
template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::
-dout_emergency_to_file_and_syslog(const char * const str) const
+emergency_log_to_file_and_syslog(const char * const str) const
{
int len = strlen(str);
if (ofd >= 0) {
*/
void dout_emergency(const char * const str)
{
+ // Write to stderr. It may or may not be open, but if it is, there's a good
+ // chance the user will see this.
int len = strlen(str);
if (safe_write(STDERR_FILENO, str, len)) {
// ignore errors
;
}
- /* Normally we would take the lock before even checking _doss, but since
- * this is an emergency, we can't do that. */
- if (_doss) {
- _doss->dout_emergency_to_file_and_syslog(str);
+
+ // Write to all the file descriptors we know about.
+ // If we are logging to syslog, send logs to that too.
+ simple_spin_lock(&dout_emergency_lock);
+ for (size_t i = 0; i < NUM_DOUT_EMERG_STREAMS; ++i) {
+ if (dout_emerg_streams[i]) {
+ dout_emerg_streams[i]->emergency_log_to_file_and_syslog(str);
+ }
}
+ simple_spin_unlock(&dout_emergency_lock);
}
void dout_emergency(const std::string &str)