/*
 * Copyright (c) 2019 Peter Bigot Consulting, LLC
 * Copyright (c) 2020 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <zephyr/sys/notify.h>

int sys_notify_validate(struct sys_notify *notify)
{
	int rv = 0;

	if (notify == NULL) {
		return -EINVAL;
	}

	/* Validate configuration based on mode */
	switch (sys_notify_get_method(notify)) {
	case SYS_NOTIFY_METHOD_SPINWAIT:
		break;
	case SYS_NOTIFY_METHOD_CALLBACK:
		if (notify->method.callback == NULL) {
			rv = -EINVAL;
		}
		break;
#ifdef CONFIG_POLL
	case SYS_NOTIFY_METHOD_SIGNAL:
		if (notify->method.signal == NULL) {
			rv = -EINVAL;
		}
		break;
#endif /* CONFIG_POLL */
	default:
		rv = -EINVAL;
		break;
	}

	/* Clear the result here instead of in all callers. */
	if (rv == 0) {
		notify->result = 0;
	}

	return rv;
}

sys_notify_generic_callback sys_notify_finalize(struct sys_notify *notify,
						    int res)
{
	struct k_poll_signal *sig = NULL;
	sys_notify_generic_callback rv = NULL;
	uint32_t method = sys_notify_get_method(notify);

	/* Store the result and capture secondary notification
	 * information.
	 */
	notify->result = res;
	switch (method) {
	case SYS_NOTIFY_METHOD_SPINWAIT:
		break;
	case SYS_NOTIFY_METHOD_CALLBACK:
		rv = notify->method.callback;
		break;
	case SYS_NOTIFY_METHOD_SIGNAL:
		sig = notify->method.signal;
		break;
	default:
		__ASSERT_NO_MSG(false);
	}

	/* Mark completion by clearing the flags field to the
	 * completed state, releasing any spin-waiters, then complete
	 * secondary notification.
	 */
	compiler_barrier();
	notify->flags = SYS_NOTIFY_METHOD_COMPLETED;

	if (IS_ENABLED(CONFIG_POLL) && (sig != NULL)) {
		k_poll_signal_raise(sig, res);
	}

	return rv;
}
