Exemple #1
0
/**
 * Create new aging container, where keys/values expire and need to be freed.
 * Values are either integers (cast to pointers) or refer to real objects.
 *
 * @param delay		the aging delay, in seconds, for entries
 * @param hash		the hashing function for the keys in the hash table
 * @param eq		the equality function for the keys in the hash table
 * @param kvfree	the key/value pair freeing callback, NULL if none.
 *
 * @return opaque handle to the container.
 */
aging_table_t *
aging_make(int delay, hash_fn_t hash, eq_fn_t eq, free_keyval_fn_t kvfree)
{
	aging_table_t *ag;

	WALLOC0(ag);
	ag->magic = AGING_MAGIC;
	ag->table = hikset_create_any(
		offsetof(struct aging_value, key),
		NULL == hash ? pointer_hash : hash, eq);
	ag->kvfree = kvfree;
	delay = MAX(delay, 1);
	delay = MIN(delay, INT_MAX / 1000);
	ag->delay = delay;
	elist_init(&ag->list, offsetof(struct aging_value, lk));

	/*
	 * If the callout queue does not run in the thread that is creating
	 * this table, then concurrent accesses are bound to happen.
	 * Therefore, make the table thread-safe.
	 */

	if (cq_main_thread_id() != thread_small_id())
		aging_thread_safe(ag);

	ag->gc_ev = cq_periodic_main_add(AGING_CALLOUT, aging_gc, ag);

	aging_check(ag);
	return ag;
}
Exemple #2
0
/**
 * Invoked when a fatal signal is received during dladdr().
 */
static G_GNUC_COLD void
dl_util_got_signal(int signo)
{
	int stid = thread_small_id();

	(void) signo;

	Siglongjmp(dl_util_env[stid], signo);
}
Exemple #3
0
NO_INLINE void G_GNUC_COLD
assertion_failure_log(const assertion_data * const data,
	const char * const fmt, ...)
{
	va_list args;
	const char *msg;

	assertion_message(data, TRUE);

	/*
	 * Record the root cause of the assertion failure to be able to log it
	 * in the crash log in case they don't have gdb available.
	 */

	crash_assert_failure(data);

	/*
	 * Record additional message in the crash log as well.
	 */

	va_start(args, fmt);
	msg = crash_assert_logv(fmt, args);
	va_end(args);

	/*
	 * Log additional message.
	 */

	if (msg != NULL) {
		char time_buf[18];
		char prefix[UINT_DEC_BUFLEN + CONST_STRLEN(" (FATAL-): ")];
		unsigned stid = thread_small_id();
		DECLARE_STR(4);

		crash_time(time_buf, sizeof time_buf);

		print_str(time_buf);
		if (0 == stid) {
			print_str(" (FATAL): ");
		} else {
			str_bprintf(prefix, sizeof prefix, " (FATAL-%u): ", stid);
			print_str(prefix);
		}
		print_str(msg);
		print_str("\n");
		flush_err_str();
		if (log_stdout_is_distinct())
			flush_str(STDOUT_FILENO);
	}

	assertion_abort();
}
Exemple #4
0
NO_INLINE void G_GNUC_COLD
assertion_warning_log(const assertion_data * const data,
	const char * const fmt, ...)
{
	static str_t *str;
	va_list args;

	assertion_message(data, FALSE);

	if G_UNLIKELY(NULL == str)
		str = str_new_not_leaking(512);

	/*
	 * Log additional message.
	 */

	va_start(args, fmt);
	str_vprintf(str, fmt, args);
	va_end(args);

	{
		char time_buf[18];
		char prefix[UINT_DEC_BUFLEN + CONST_STRLEN(" (WARNING-): ")];
		unsigned stid = thread_small_id();
		DECLARE_STR(4);

		crash_time(time_buf, sizeof time_buf);

		print_str(time_buf);
		if (0 == stid) {
			print_str(" (WARNING): ");
		} else {
			str_bprintf(prefix, sizeof prefix, " (WARNING-%u): ", stid);
			print_str(prefix);
		}
		print_str(str_2c(str));
		print_str("\n");
		flush_err_str();
		if (log_stdout_is_distinct())
			flush_str(STDOUT_FILENO);
	}

	assertion_stacktrace();
}
Exemple #5
0
/**
 * @note For maximum safety this is kept signal-safe, so that we can
 *       even use assertions in signal handlers. See also:
 * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
 */
static G_GNUC_COLD void
assertion_message(const assertion_data * const data, int fatal)
{
	char line_buf[22];
	char time_buf[18];
	char prefix[UINT_DEC_BUFLEN + CONST_STRLEN(" (WARNING-): ")];
	unsigned stid;
	DECLARE_STR(16);

	crash_time(time_buf, sizeof time_buf);
	stid = thread_small_id();

	print_str(time_buf);
	if (0 == stid) {
		print_str(fatal ? " (FATAL): " : " (WARNING): ");
	} else {
		str_bprintf(prefix, sizeof prefix, " (%s-%u): ",
			fatal ? "FATAL" : "WARNING", stid);
		print_str(prefix);
	}
	if (data->expr) {
		print_str("Assertion failure at ");
	} else {
		print_str("Code should not have been reached at ");
	}
	print_str(data->file);
	print_str(":");
	print_str(print_number(line_buf, sizeof line_buf, data->line));
	if (data->expr) {
		print_str(": \"");
		print_str(data->expr);
		print_str("\"");
	}
	print_str("\n");
	flush_err_str();
	if (log_stdout_is_distinct())
		flush_str(STDOUT_FILENO);
}
Exemple #6
0
/**
 * Log message.
 */
void
gl_logv(const char *domain, GLogLevelFlags flags, const char *fmt, va_list args)
{
	static str_t *msg[THREAD_MAX];
	static bool logging[THREAD_MAX];
	unsigned stid = thread_small_id();

	G_IGNORE_PUSH(-Wformat-nonliteral);		/* s_minilogv() call below */

	if (logging[stid]) {
		s_minilogv(flags | G_LOG_FLAG_RECURSION, FALSE, fmt, args);
		return;
	}

	G_IGNORE_POP;

	/*
	 * This call is thread-unsafe by construction, and supposed to be called
	 * only from the main thread.  This is why it's OK to have a global
	 * ``logging'' variable.
	 */

	logging[stid] = TRUE;

	if G_UNLIKELY(NULL == msg[stid])
		msg[stid] = str_new_not_leaking(0);

	str_vprintf(msg[stid], fmt, args);

	if (handler_cb != NULL)
		(*handler_cb)(domain, flags, str_2c(msg[stid]), handler_data);
	else
		s_minilog(flags, "%s", str_2c(msg[stid]));

	logging[stid] = FALSE;
}
/**
 * @note For maximum safety this is kept signal-safe, so that we can
 *       even use assertions in signal handlers. See also:
 * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
 */
static G_GNUC_COLD void
assertion_message(const assertion_data * const data, int fatal)
{
	char line_buf[ULONG_DEC_BUFLEN];
	char time_buf[CRASH_TIME_BUFLEN];
	char prefix[UINT_DEC_BUFLEN + CONST_STRLEN(" (WARNING-): ")];
	unsigned stid, line;
	bool assertion;
	DECLARE_STR(16);

	crash_time(time_buf, sizeof time_buf);
	stid = thread_small_id();

	/*
	 * When an assertion failed in some thread, things are likely to break in
	 * all the other threads and we want to avoid a cascade of failures being
	 * reported.  We suspend after computing the crash time, in case we were
	 * not suspended due to a fatal error.
	 */

	thread_check_suspended();

	print_str(time_buf);
	if (0 == stid) {
		print_str(fatal ? " (FATAL): " : " (WARNING): ");
	} else {
		str_bprintf(prefix, sizeof prefix, " (%s-%u): ",
			fatal ? "FATAL" : "WARNING", stid);
		print_str(prefix);
	}

	/*
	 * If the FAST_ASSERT_NOT_REACHED bit is set in the line number,
	 * then it does not indicate an assertion failure but rather that
	 * we reached a point in the code that should never have been reached.
	 *		--RAM, 2013-10-28
	 */

	line = data->line & ~FAST_ASSERT_NOT_REACHED;
	assertion = line == data->line;

	if (assertion) {
		print_str("Assertion failure at ");
	} else {
		print_str("Code should not have been reached in ");
		print_str(data->expr);		/* Routine name */
		print_str("() at ");
	}
	print_str(data->file);
	print_str(":");
	print_str(PRINT_NUMBER(line_buf, line));
	if (assertion) {
		print_str(": \"");
		print_str(data->expr);
		print_str("\"");
	}
	print_str("\n");
	flush_err_str_atomic();
	if (log_stdout_is_distinct())
		flush_str_atomic(STDOUT_FILENO);
}
Exemple #8
0
/**
 * Perform specify operation on the address.
 *
 * @param addr		the address we're querying
 * @param op		the operation to perform
 *
 * @return NULL on failure, an address whose interpretation is op-specific
 * otherwise.
 */
static const void *
dl_util_query(const void *addr, enum dl_addr_op op)
{
	if G_UNLIKELY(!dl_util_inited)
		dl_util_init();

#ifdef HAS_DLADDR
	{
		static Dl_info info;
		static const void *last_addr;
		int stid = thread_small_id();

		/*
		 * Cache results for a given address.  This will help our stack
		 * pretty-printing code which is going to gather the various
		 * items at different times instead of doing one dladdr() call.
		 * For a given stack item, we may therefore face various calls
		 * for the same address.
		 *
		 * The rationale is that we may want to use different routines on
		 * another platform without dladdr() some days and therefore we wish
		 * to hide the existence of dladdr() and rather provide higher-level
		 * services like dl_util_get_base().
		 */

		if (addr != last_addr) {
			signal_handler_t old_sigsegv;
			int ret;

			ZERO(&info);

			/*
			 * Protect against segmentation faults in dladdr().
			 *
			 * We use signal_catch() instead of signal_set() because we
			 * don't need extra information about the fault context.
			 */

			old_sigsegv = signal_catch(SIGSEGV, dl_util_got_signal);

			if (Sigsetjmp(dl_util_env[stid], TRUE)) {
				last_addr = NULL;
				return NULL;
			}

			ret = dladdr(deconstify_pointer(addr), &info);
			signal_set(SIGSEGV, old_sigsegv);

			if (0 == ret) {
				last_addr = NULL;
				return NULL;
			}
			last_addr = addr;
		}

		switch (op) {
		case DL_ADDR_GET_BASE:
			return info.dli_fbase;
		case DL_ADDR_GET_NAME:
			return info.dli_sname;
		case DL_ADDR_GET_PATH:
			return info.dli_fname;
		case DL_ADDR_GET_START:
			return info.dli_saddr;
		}
	}

	g_assert_not_reached();
#else	/* !HAS_DLADDR */
	(void) addr;
	(void) op;

	return NULL;
#endif	/* HAS_DLADDR */
}