2 *------------------------------------------------------------------
3 * svmdb.c -- simple shared memory database
5 * Copyright (c) 2009 Cisco and/or its affiliates.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
22 #include <sys/types.h>
25 #include <netinet/in.h>
32 #include <vppinfra/clib.h>
33 #include <vppinfra/vec.h>
34 #include <vppinfra/hash.h>
35 #include <vppinfra/bitmap.h>
36 #include <vppinfra/fifo.h>
37 #include <vppinfra/time.h>
38 #include <vppinfra/mheap.h>
39 #include <vppinfra/heap.h>
40 #include <vppinfra/pool.h>
41 #include <vppinfra/format.h>
45 static void local_set_variable_nolock (svmdb_client_t * client,
46 svmdb_namespace_t namespace,
47 u8 * var, u8 * val, u32 elsize);
50 region_lock (svm_region_t * rp, int tag)
52 pthread_mutex_lock (&rp->mutex);
54 rp->mutex_owner_pid = getpid ();
55 rp->mutex_owner_tag = tag;
60 region_unlock (svm_region_t * rp)
63 rp->mutex_owner_pid = 0;
64 rp->mutex_owner_tag = 0;
66 pthread_mutex_unlock (&rp->mutex);
69 static svmdb_client_t *
70 svmdb_map_internal (char *root_path, uword size)
72 svmdb_client_t *client = 0;
73 svm_map_region_args_t *a = 0;
76 svmdb_shm_hdr_t *hp = 0;
78 vec_validate (client, 0);
81 svm_region_init_chroot (root_path);
83 a->root_path = root_path;
85 a->size = size ? size : SVMDB_DEFAULT_SIZE;
86 a->flags = SVM_FLAGS_MHEAP;
88 db_rp = client->db_rp = svm_region_find_or_create (a);
94 region_lock (client->db_rp, 10);
95 /* Has someone else set up the shared-memory variable table? */
98 client->shm = (void *) db_rp->user_ctx;
99 client->pid = getpid ();
100 region_unlock (client->db_rp);
101 ASSERT (client->shm->version == SVMDB_SHM_VERSION);
104 /* Nope, it's our problem... */
106 /* Add a bogus client (pid=0) so the svm won't be deallocated */
107 oldheap = svm_push_pvt_heap (db_rp);
108 vec_add1 (client->db_rp->client_pids, 0);
109 svm_pop_heap (oldheap);
111 oldheap = svm_push_data_heap (db_rp);
113 vec_validate (hp, 0);
114 hp->version = SVMDB_SHM_VERSION;
115 hp->namespaces[SVMDB_NAMESPACE_STRING]
116 = hash_create_string (0, sizeof (uword));
117 hp->namespaces[SVMDB_NAMESPACE_VEC]
118 = hash_create_string (0, sizeof (uword));
120 db_rp->user_ctx = hp;
123 svm_pop_heap (oldheap);
124 region_unlock (client->db_rp);
125 client->pid = getpid ();
133 return svmdb_map_internal (0, 0);
137 svmdb_map_size (uword size)
139 return svmdb_map_internal (0, size);
143 svmdb_map_chroot (char *root_path)
145 return svmdb_map_internal (root_path, 0);
149 svmdb_map_chroot_size (char *root_path, uword size)
151 return svmdb_map_internal (root_path, size);
155 svmdb_unmap (svmdb_client_t * client)
159 if (!svm_get_root_rp ())
162 svm_region_unmap ((void *) client->db_rp);
168 notify_value (svmdb_value_t * v, svmdb_action_t a)
174 u32 *dead_registrations = 0;
178 for (i = 0; i < vec_len (v->notifications); i++)
180 np = vec_elt_at_index (v->notifications, i);
183 value = (np->action << 28) | (np->opaque);
184 sv.sival_ptr = (void *) (uword) value;
188 if (sigqueue (np->pid, np->signum, sv) == 0)
192 while (rv == EAGAIN);
195 vec_add1 (dead_registrations, i);
199 for (i = 0; i < vec_len (dead_registrations); i++)
201 np = vec_elt_at_index (v->notifications, dead_registrations[i]);
202 clib_warning ("dead reg pid %d sig %d action %d opaque %x",
203 np->pid, np->signum, np->action, np->opaque);
204 vec_delete (v->notifications, 1, dead_registrations[i]);
206 vec_free (dead_registrations);
210 svmdb_local_add_del_notification (svmdb_client_t * client,
211 svmdb_notification_args_t * a)
216 svmdb_shm_hdr_t *shm;
218 svmdb_value_t *value;
225 region_lock (client->db_rp, 18);
227 oldheap = svm_push_data_heap (client->db_rp);
229 h = shm->namespaces[a->nspace];
231 hp = hash_get_pair_mem (h, a->var);
234 local_set_variable_nolock (client, a->nspace, (u8 *) a->var,
235 dummy_value, a->elsize);
236 /* might have moved */
237 h = shm->namespaces[a->nspace];
238 hp = hash_get_pair_mem (h, a->var);
242 value = pool_elt_at_index (shm->values, hp->value[0]);
244 for (i = 0; i < vec_len (value->notifications); i++)
246 np = vec_elt_at_index (value->notifications, i);
247 if ((np->pid == client->pid)
248 && (np->signum == a->signum)
249 && (np->action == a->action) && (np->opaque == a->opaque))
251 if (a->add_del == 0 /* delete */ )
253 vec_delete (value->notifications, 1, i);
259 ("%s: ignore dup reg pid %d signum %d action %d opaque %x",
260 a->var, client->pid, a->signum, a->action, a->opaque);
272 vec_add2 (value->notifications, np, 1);
273 np->pid = client->pid;
274 np->signum = a->signum;
275 np->action = a->action;
276 np->opaque = a->opaque;
279 svm_pop_heap (oldheap);
280 region_unlock (client->db_rp);
286 local_unset_variable_nolock (svmdb_client_t * client,
287 svmdb_namespace_t namespace, char *var)
290 svmdb_value_t *oldvalue;
293 h = client->shm->namespaces[namespace];
294 hp = hash_get_pair_mem (h, var);
297 oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
298 if (vec_len (oldvalue->notifications))
299 notify_value (oldvalue, SVMDB_ACTION_UNSET);
300 /* zero length value means unset */
301 _vec_len (oldvalue->value) = 0;
303 client->shm->namespaces[namespace] = h;
307 svmdb_local_unset_string_variable (svmdb_client_t * client, char *var)
311 region_lock (client->db_rp, 11);
312 oldheap = svm_push_data_heap (client->db_rp);
313 local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var);
314 svm_pop_heap (oldheap);
315 region_unlock (client->db_rp);
319 local_set_variable_nolock (svmdb_client_t * client,
320 svmdb_namespace_t namespace,
321 u8 * var, u8 * val, u32 elsize)
326 svmdb_shm_hdr_t *shm;
329 h = shm->namespaces[namespace];
330 hp = hash_get_pair_mem (h, var);
333 svmdb_value_t *oldvalue;
334 oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
335 vec_alloc (oldvalue->value, vec_len (val) * elsize);
336 clib_memcpy (oldvalue->value, val, vec_len (val) * elsize);
337 _vec_len (oldvalue->value) = vec_len (val);
338 notify_value (oldvalue, SVMDB_ACTION_SET);
342 svmdb_value_t *newvalue;
343 pool_get (shm->values, newvalue);
344 memset (newvalue, 0, sizeof (*newvalue));
345 newvalue->elsize = elsize;
346 vec_alloc (newvalue->value, vec_len (val) * elsize);
347 clib_memcpy (newvalue->value, val, vec_len (val) * elsize);
348 _vec_len (newvalue->value) = vec_len (val);
349 name = format (0, "%s%c", var, 0);
350 hash_set_mem (h, name, newvalue - shm->values);
352 shm->namespaces[namespace] = h;
356 svmdb_local_set_string_variable (svmdb_client_t * client,
357 char *var, char *val)
361 region_lock (client->db_rp, 12);
362 oldheap = svm_push_data_heap (client->db_rp);
364 local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var);
366 local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING,
367 (u8 *) var, (u8 *) val, 1 /* elsize */ );
368 svm_pop_heap (oldheap);
369 region_unlock (client->db_rp);
373 local_get_variable_nolock (svmdb_client_t * client,
374 svmdb_namespace_t namespace, u8 * var)
378 svmdb_shm_hdr_t *shm;
379 svmdb_value_t *oldvalue;
382 h = shm->namespaces[namespace];
383 p = hash_get_mem (h, var);
386 oldvalue = pool_elt_at_index (shm->values, p[0]);
387 notify_value (oldvalue, SVMDB_ACTION_GET);
388 return (oldvalue->value);
394 svmdb_local_get_variable_reference (svmdb_client_t * client,
395 svmdb_namespace_t namespace, char *var)
399 region_lock (client->db_rp, 19);
400 rv = local_get_variable_nolock (client, namespace, (u8 *) var);
401 region_unlock (client->db_rp);
406 svmdb_local_get_string_variable (svmdb_client_t * client, char *var)
410 region_lock (client->db_rp, 13);
411 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_STRING, (u8 *) var);
413 if (rv && vec_len (rv))
415 rv = format (0, "%s", rv);
418 region_unlock (client->db_rp);
419 return ((char *) rv);
423 svmdb_local_dump_strings (svmdb_client_t * client)
428 svmdb_shm_hdr_t *shm = client->shm;
430 region_lock (client->db_rp, 14);
432 h = client->shm->namespaces[SVMDB_NAMESPACE_STRING];
435 hash_foreach_mem(key, value, h,
437 svmdb_value_t *v = pool_elt_at_index (shm->values, value);
439 fformat(stdout, "%s: %s\n", key,
440 vec_len(v->value) ? v->value : (u8 *)"(nil)");
443 region_unlock (client->db_rp);
447 svmdb_local_unset_vec_variable (svmdb_client_t * client, char *var)
451 region_lock (client->db_rp, 15);
452 oldheap = svm_push_data_heap (client->db_rp);
453 local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var);
454 svm_pop_heap (oldheap);
455 region_unlock (client->db_rp);
459 svmdb_local_set_vec_variable (svmdb_client_t * client,
460 char *var, void *val_arg, u32 elsize)
462 u8 *val = (u8 *) val_arg;
465 region_lock (client->db_rp, 16);
466 oldheap = svm_push_data_heap (client->db_rp);
468 local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var);
469 local_set_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var,
472 svm_pop_heap (oldheap);
473 region_unlock (client->db_rp);
477 svmdb_local_get_vec_variable (svmdb_client_t * client, char *var, u32 elsize)
482 region_lock (client->db_rp, 17);
484 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
486 if (rv && vec_len (rv))
488 /* Make a copy in process-local memory */
489 vec_alloc (copy, vec_len (rv) * elsize);
490 clib_memcpy (copy, rv, vec_len (rv) * elsize);
491 _vec_len (copy) = vec_len (rv);
492 region_unlock (client->db_rp);
495 region_unlock (client->db_rp);
500 svmdb_local_dump_vecs (svmdb_client_t * client)
505 svmdb_shm_hdr_t *shm;
507 region_lock (client->db_rp, 17);
510 h = client->shm->namespaces[SVMDB_NAMESPACE_VEC];
513 hash_foreach_mem(key, value, h,
515 svmdb_value_t *v = pool_elt_at_index (shm->values, value);
516 (void) fformat(stdout, "%s:\n %U (%.2f)\n", key,
517 format_hex_bytes, v->value,
518 vec_len(v->value)*v->elsize, ((f64 *)(v->value))[0]);
522 region_unlock (client->db_rp);
526 svmdb_local_find_or_add_vec_variable (svmdb_client_t * client,
527 char *var, u32 nbytes)
532 region_lock (client->db_rp, 18);
533 oldheap = svm_push_data_heap (client->db_rp);
535 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
545 svmdb_shm_hdr_t *shm;
546 svmdb_value_t *newvalue;
549 h = shm->namespaces[SVMDB_NAMESPACE_VEC];
551 pool_get (shm->values, newvalue);
552 memset (newvalue, 0, sizeof (*newvalue));
553 newvalue->elsize = 1;
554 vec_alloc (newvalue->value, nbytes);
555 _vec_len (newvalue->value) = nbytes;
556 name = format (0, "%s%c", var, 0);
557 hash_set_mem (h, name, newvalue - shm->values);
558 shm->namespaces[SVMDB_NAMESPACE_VEC] = h;
559 rv = newvalue->value;
563 svm_pop_heap (oldheap);
564 region_unlock (client->db_rp);
569 * fd.io coding-style-patch-verification: ON
572 * eval: (c-set-style "gnu")