1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/queue.h> 35 36 #include "spdk/stdinc.h" 37 #include "spdk/util.h" 38 #include "spdk/queue.h" 39 #include "spdk/string.h" 40 #include "spdk/log.h" 41 42 #include "spdk/notify.h" 43 44 #define SPDK_NOTIFY_MAX_EVENTS 1024 45 46 struct spdk_notify_type { 47 char name[SPDK_NOTIFY_MAX_NAME_SIZE]; 48 TAILQ_ENTRY(spdk_notify_type) tailq; 49 }; 50 51 pthread_mutex_t g_events_lock = PTHREAD_MUTEX_INITIALIZER; 52 static struct spdk_notify_event g_events[SPDK_NOTIFY_MAX_EVENTS]; 53 static uint64_t g_events_head; 54 55 static TAILQ_HEAD(, spdk_notify_type) g_notify_types = TAILQ_HEAD_INITIALIZER(g_notify_types); 56 57 struct spdk_notify_type * 58 spdk_notify_type_register(const char *type) 59 { 60 struct spdk_notify_type *it = NULL; 61 62 if (!type) { 63 SPDK_ERRLOG("Invalid notification type %p\n", type); 64 return NULL; 65 } else if (!type[0] || strlen(type) >= SPDK_NOTIFY_MAX_NAME_SIZE) { 66 SPDK_ERRLOG("Notification type '%s' too short or too long\n", type); 67 return NULL; 68 } 69 70 pthread_mutex_lock(&g_events_lock); 71 TAILQ_FOREACH(it, &g_notify_types, tailq) { 72 if (strcmp(type, it->name) == 0) { 73 SPDK_ERRLOG("Notification type '%s' already registered.\n", type); 74 goto out; 75 } 76 } 77 78 it = calloc(1, sizeof(*it)); 79 if (it == NULL) { 80 goto out; 81 } 82 83 snprintf(it->name, sizeof(it->name), "%s", type); 84 TAILQ_INSERT_TAIL(&g_notify_types, it, tailq); 85 86 out: 87 pthread_mutex_unlock(&g_events_lock); 88 return it; 89 } 90 91 const char * 92 spdk_notify_type_get_name(const struct spdk_notify_type *type) 93 { 94 return type->name; 95 } 96 97 98 void 99 spdk_notify_foreach_type(spdk_notify_foreach_type_cb cb, void *ctx) 100 { 101 struct spdk_notify_type *it; 102 103 pthread_mutex_lock(&g_events_lock); 104 TAILQ_FOREACH(it, &g_notify_types, tailq) { 105 if (cb(it, ctx)) { 106 break; 107 } 108 } 109 pthread_mutex_unlock(&g_events_lock); 110 } 111 112 uint64_t 113 spdk_notify_send(const char *type, const char *ctx) 114 { 115 uint64_t head; 116 struct spdk_notify_event *ev; 117 118 pthread_mutex_lock(&g_events_lock); 119 head = g_events_head; 120 g_events_head++; 121 122 ev = &g_events[head % SPDK_NOTIFY_MAX_EVENTS]; 123 spdk_strcpy_pad(ev->type, type, sizeof(ev->type), '\0'); 124 spdk_strcpy_pad(ev->ctx, ctx, sizeof(ev->ctx), '\0'); 125 pthread_mutex_unlock(&g_events_lock); 126 127 return head; 128 } 129 130 uint64_t 131 spdk_notify_foreach_event(uint64_t start_idx, uint64_t max, 132 spdk_notify_foreach_event_cb cb_fn, void *ctx) 133 { 134 uint64_t i; 135 136 pthread_mutex_lock(&g_events_lock); 137 138 if (g_events_head > SPDK_NOTIFY_MAX_EVENTS && start_idx < g_events_head - SPDK_NOTIFY_MAX_EVENTS) { 139 start_idx = g_events_head - SPDK_NOTIFY_MAX_EVENTS; 140 } 141 142 for (i = 0; start_idx < g_events_head && i < max; start_idx++, i++) { 143 if (cb_fn(start_idx, &g_events[start_idx % SPDK_NOTIFY_MAX_EVENTS], ctx)) { 144 break; 145 } 146 } 147 pthread_mutex_unlock(&g_events_lock); 148 149 return i; 150 } 151