xref: /spdk/lib/notify/notify.c (revision 2b46c17df1ed540c34053c2143274e185c302bee)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2018 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include <sys/queue.h>
7 
8 #include "spdk/stdinc.h"
9 #include "spdk/util.h"
10 #include "spdk/queue.h"
11 #include "spdk/string.h"
12 #include "spdk/log.h"
13 
14 #include "spdk/notify.h"
15 
16 #define SPDK_NOTIFY_MAX_EVENTS	1024
17 
18 struct spdk_notify_type {
19 	char name[SPDK_NOTIFY_MAX_NAME_SIZE];
20 	TAILQ_ENTRY(spdk_notify_type) tailq;
21 };
22 
23 static pthread_mutex_t g_events_lock = PTHREAD_MUTEX_INITIALIZER;
24 static struct spdk_notify_event g_events[SPDK_NOTIFY_MAX_EVENTS];
25 static uint64_t g_events_head;
26 
27 static TAILQ_HEAD(, spdk_notify_type) g_notify_types = TAILQ_HEAD_INITIALIZER(g_notify_types);
28 
29 struct spdk_notify_type *
30 spdk_notify_type_register(const char *type)
31 {
32 	struct spdk_notify_type *it = NULL;
33 
34 	if (!type) {
35 		SPDK_ERRLOG("Invalid notification type %p\n", type);
36 		return NULL;
37 	} else if (!type[0] || strlen(type) >= SPDK_NOTIFY_MAX_NAME_SIZE) {
38 		SPDK_ERRLOG("Notification type '%s' too short or too long\n", type);
39 		return NULL;
40 	}
41 
42 	pthread_mutex_lock(&g_events_lock);
43 	TAILQ_FOREACH(it, &g_notify_types, tailq) {
44 		if (strcmp(type, it->name) == 0) {
45 			SPDK_NOTICELOG("Notification type '%s' already registered.\n", type);
46 			goto out;
47 		}
48 	}
49 
50 	it = calloc(1, sizeof(*it));
51 	if (it == NULL) {
52 		goto out;
53 	}
54 
55 	snprintf(it->name, sizeof(it->name), "%s", type);
56 	TAILQ_INSERT_TAIL(&g_notify_types, it, tailq);
57 
58 out:
59 	pthread_mutex_unlock(&g_events_lock);
60 	return it;
61 }
62 
63 const char *
64 spdk_notify_type_get_name(const struct spdk_notify_type *type)
65 {
66 	return type->name;
67 }
68 
69 
70 void
71 spdk_notify_foreach_type(spdk_notify_foreach_type_cb cb, void *ctx)
72 {
73 	struct spdk_notify_type *it;
74 
75 	pthread_mutex_lock(&g_events_lock);
76 	TAILQ_FOREACH(it, &g_notify_types, tailq) {
77 		if (cb(it, ctx)) {
78 			break;
79 		}
80 	}
81 	pthread_mutex_unlock(&g_events_lock);
82 }
83 
84 uint64_t
85 spdk_notify_send(const char *type, const char *ctx)
86 {
87 	uint64_t head;
88 	struct spdk_notify_event *ev;
89 
90 	pthread_mutex_lock(&g_events_lock);
91 	head = g_events_head;
92 	g_events_head++;
93 
94 	ev = &g_events[head % SPDK_NOTIFY_MAX_EVENTS];
95 	spdk_strcpy_pad(ev->type, type, sizeof(ev->type), '\0');
96 	spdk_strcpy_pad(ev->ctx, ctx, sizeof(ev->ctx), '\0');
97 	pthread_mutex_unlock(&g_events_lock);
98 
99 	return head;
100 }
101 
102 uint64_t
103 spdk_notify_foreach_event(uint64_t start_idx, uint64_t max,
104 			  spdk_notify_foreach_event_cb cb_fn, void *ctx)
105 {
106 	uint64_t i;
107 
108 	pthread_mutex_lock(&g_events_lock);
109 
110 	if (g_events_head > SPDK_NOTIFY_MAX_EVENTS && start_idx < g_events_head - SPDK_NOTIFY_MAX_EVENTS) {
111 		start_idx = g_events_head - SPDK_NOTIFY_MAX_EVENTS;
112 	}
113 
114 	for (i = 0; start_idx < g_events_head && i < max; start_idx++, i++) {
115 		if (cb_fn(start_idx, &g_events[start_idx % SPDK_NOTIFY_MAX_EVENTS], ctx)) {
116 			break;
117 		}
118 	}
119 	pthread_mutex_unlock(&g_events_lock);
120 
121 	return i;
122 }
123