FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
memory_api.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17 #include <signal.h>
18 
19 #include <vlib/vlib.h>
20 #include <vlibapi/api.h>
21 #include <vlibmemory/api.h>
22 #include <vlibmemory/memory_api.h>
23 
24 #include <vlibmemory/vl_memory_msg_enum.h> /* enumerate all vlib messages */
25 
26 #define vl_typedefs /* define message structures */
28 #undef vl_typedefs
29 
30 /* instantiate all the print functions we know about */
31 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
32 #define vl_printfun
34 #undef vl_printfun
35 
36 /* instantiate all the endian swap functions we know about */
37 #define vl_endianfun
39 #undef vl_endianfun
40 
41 static inline void *
43 {
44  vl_print (handle, "vl_api_memclnt_create_t:\n");
45  vl_print (handle, "name: %s\n", a->name);
46  vl_print (handle, "input_queue: 0x%wx\n", a->input_queue);
47  vl_print (handle, "context: %u\n", (unsigned) a->context);
48  vl_print (handle, "ctx_quota: %ld\n", (long) a->ctx_quota);
49  return handle;
50 }
51 
52 static inline void *
54 {
55  vl_print (handle, "vl_api_memclnt_delete_t:\n");
56  vl_print (handle, "index: %u\n", (unsigned) a->index);
57  vl_print (handle, "handle: 0x%wx\n", a->handle);
58  return handle;
59 }
60 
61 volatile int **vl_api_queue_cursizes;
62 
63 static void
65 {
66  int i;
68  int have_pending_rpcs;
69 
71  1 + vec_len (am->vlib_private_rps)))
72  {
73  vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
74  svm_queue_t *q;
75 
76  if (shmem_hdr == 0)
77  return;
78 
79  q = shmem_hdr->vl_input_queue;
80  if (q == 0)
81  return;
82 
83  vec_add1 (vl_api_queue_cursizes, &q->cursize);
84 
85  for (i = 0; i < vec_len (am->vlib_private_rps); i++)
86  {
87  svm_region_t *vlib_rp = am->vlib_private_rps[i];
88 
89  shmem_hdr = (void *) vlib_rp->user_ctx;
90  q = shmem_hdr->vl_input_queue;
91  vec_add1 (vl_api_queue_cursizes, &q->cursize);
92  }
93  }
94 
95  for (i = 0; i < vec_len (vl_api_queue_cursizes); i++)
96  {
98  {
100  vm->api_queue_nonempty = 1;
102  /* event_type */ QUEUE_SIGNAL_EVENT,
103  /* event_data */ 0);
104  break;
105  }
106  }
107 
109  have_pending_rpcs = vec_len (vm->pending_rpc_requests) > 0;
111 
112  if (have_pending_rpcs)
113  {
115  vm->api_queue_nonempty = 1;
117  /* event_type */ QUEUE_SIGNAL_EVENT,
118  /* event_data */ 0);
119  }
120 }
121 
122 /*
123  * vl_api_memclnt_create_internal
124  */
125 u32
127 {
128  vl_api_registration_t **regpp;
129  vl_api_registration_t *regp;
130  void *oldheap;
132 
133  ASSERT (vlib_get_thread_index () == 0);
134  pool_get (am->vl_clients, regpp);
135 
136 
137  oldheap = vl_msg_push_heap ();
138  *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
139 
140  regp = *regpp;
141  clib_memset (regp, 0, sizeof (*regp));
143  regp->vl_api_registration_pool_index = regpp - am->vl_clients;
144  regp->vlib_rp = am->vlib_rp;
145  regp->shmem_hdr = am->shmem_hdr;
146 
147  regp->vl_input_queue = q;
148  regp->name = format (0, "%s%c", name, 0);
149 
150  vl_msg_pop_heap (oldheap);
153  am->shmem_hdr->application_restarts);
154 }
155 
156 /*
157  * vl_api_memclnt_create_t_handler
158  */
159 void
161 {
162  vl_api_registration_t **regpp;
163  vl_api_registration_t *regp;
165  svm_queue_t *q;
166  int rv = 0;
167  void *oldheap;
169  u8 *msg_table;
170 
171  /*
172  * This is tortured. Maintain a vlib-address-space private
173  * pool of client registrations. We use the shared-memory virtual
174  * address of client structure as a handle, to allow direct
175  * manipulation of context quota vbls from the client library.
176  *
177  * This scheme causes trouble w/ API message trace replay, since
178  * some random VA from clib_mem_alloc() certainly won't
179  * occur in the Linux sim. The (very) few places
180  * that care need to use the pool index.
181  *
182  * Putting the registration object(s) into a pool in shared memory and
183  * using the pool index as a handle seems like a great idea.
184  * Unfortunately, each and every reference to that pool would need
185  * to be protected by a mutex:
186  *
187  * Client VLIB
188  * ------ ----
189  * convert pool index to
190  * pointer.
191  * <deschedule>
192  * expand pool
193  * <deschedule>
194  * kaboom!
195  */
196 
197  pool_get (am->vl_clients, regpp);
198 
199  oldheap = vl_msg_push_heap ();
200  *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
201 
202  regp = *regpp;
203  clib_memset (regp, 0, sizeof (*regp));
205  regp->vl_api_registration_pool_index = regpp - am->vl_clients;
206  regp->vlib_rp = am->vlib_rp;
207  regp->shmem_hdr = am->shmem_hdr;
208  regp->clib_file_index = am->shmem_hdr->clib_file_index;
209 
210  q = regp->vl_input_queue = (svm_queue_t *) (uword) mp->input_queue;
212 
213  regp->name = format (0, "%s", mp->name);
214  vec_add1 (regp->name, 0);
215 
216  if (am->serialized_message_table_in_shmem == 0)
217  am->serialized_message_table_in_shmem =
219 
220  if (am->vlib_rp != am->vlib_primary_rp)
221  msg_table = vl_api_serialize_message_table (am, 0);
222  else
223  msg_table = am->serialized_message_table_in_shmem;
224 
225  vl_msg_pop_heap (oldheap);
226 
227  rp = vl_msg_api_alloc (sizeof (*rp));
228  rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_REPLY);
229  rp->handle = (uword) regp;
232  am->shmem_hdr->application_restarts);
233  rp->context = mp->context;
234  rp->response = ntohl (rv);
235  rp->message_table = pointer_to_uword (msg_table);
236 
237  vl_msg_api_send_shmem (q, (u8 *) & rp);
238 }
239 
240 void
242 {
243  clib_error_t *error = 0;
244  _vl_msg_api_function_list_elt_t *i;
245 
247  while (i)
248  {
249  error = i->f (client_index);
250  if (error)
252  i = i->next_init_function;
253  }
254 }
255 
256 /*
257  * vl_api_memclnt_delete_t_handler
258  */
259 void
261 {
262  vl_api_registration_t **regpp;
263  vl_api_registration_t *regp;
265  void *oldheap;
267  u32 handle, client_index, epoch;
268 
269  handle = mp->index;
270 
272 
273  epoch = vl_msg_api_handle_get_epoch (handle);
274  client_index = vl_msg_api_handle_get_index (handle);
275 
276  if (epoch != (am->shmem_hdr->application_restarts & VL_API_EPOCH_MASK))
277  {
279  ("Stale clnt delete index %d old epoch %d cur epoch %d",
280  client_index, epoch,
281  (am->shmem_hdr->application_restarts & VL_API_EPOCH_MASK));
282  return;
283  }
284 
285  regpp = pool_elt_at_index (am->vl_clients, client_index);
286 
287  if (!pool_is_free (am->vl_clients, regpp))
288  {
289  int i;
290  regp = *regpp;
291  int private_registration = 0;
292 
293  /* Send reply unless client asked us to do the cleanup */
294  if (!mp->do_cleanup)
295  {
296  /*
297  * Note: the API message handling path will set am->vlib_rp
298  * as appropriate for pairwise / private memory segments
299  */
300  rp = vl_msg_api_alloc (sizeof (*rp));
301  rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE_REPLY);
302  rp->handle = mp->handle;
303  rp->response = 1;
304 
305  vl_msg_api_send_shmem (regp->vl_input_queue, (u8 *) & rp);
306  if (client_index != regp->vl_api_registration_pool_index)
307  {
308  clib_warning ("mismatch client_index %d pool_index %d",
309  client_index,
311  vl_msg_api_free (rp);
312  return;
313  }
314  }
315 
316  /* No dangling references, please */
317  *regpp = 0;
318 
319  /* For horizontal scaling, add a hash table... */
320  for (i = 0; i < vec_len (am->vlib_private_rps); i++)
321  {
322  /* Is this a pairwise / private API segment? */
323  if (am->vlib_private_rps[i] == am->vlib_rp)
324  {
325  /* Note: account for the memfd header page */
326  uword virtual_base = am->vlib_rp->virtual_base - MMAP_PAGESIZE;
327  uword virtual_size = am->vlib_rp->virtual_size + MMAP_PAGESIZE;
328 
329  /*
330  * Kill the registration pool element before we make
331  * the index vanish forever
332  */
333  pool_put_index (am->vl_clients,
335 
336  vec_delete (am->vlib_private_rps, 1, i);
337  /* Kill it, accounting for the memfd header page */
338  if (munmap ((void *) virtual_base, virtual_size) < 0)
339  clib_unix_warning ("munmap");
340  /* Reset the queue-length-address cache */
342  private_registration = 1;
343  break;
344  }
345  }
346 
347  if (private_registration == 0)
348  {
349  pool_put_index (am->vl_clients,
351  oldheap = vl_msg_push_heap ();
352  if (mp->do_cleanup)
354  vec_free (regp->name);
355  /* Poison the old registration */
356  clib_memset (regp, 0xF1, sizeof (*regp));
357  clib_mem_free (regp);
358  vl_msg_pop_heap (oldheap);
359  /*
360  * These messages must be freed manually, since they're set up
361  * as "bounce" messages. In the private_registration == 1 case,
362  * we kill the shared-memory segment which contains the message
363  * with munmap.
364  */
365  vl_msg_api_free (mp);
366  }
367  }
368  else
369  {
370  clib_warning ("unknown client ID %d", mp->index);
371  }
372 }
373 
374 /**
375  * client answered a ping, stave off the grim reaper...
376  */
377 void
379  (vl_api_memclnt_keepalive_reply_t * mp)
380 {
381  vl_api_registration_t *regp;
383 
384  regp = vl_api_client_index_to_registration (mp->context);
385  if (regp)
386  {
387  regp->last_heard = vlib_time_now (vm);
388  regp->unanswered_pings = 0;
389  }
390  else
391  clib_warning ("BUG: anonymous memclnt_keepalive_reply");
392 }
393 
394 /**
395  * We can send ourselves these messages if someone uses the
396  * builtin binary api test tool...
397  */
398 static void
400 {
401  vl_api_memclnt_keepalive_reply_t *rmp;
402  api_main_t *am;
403  vl_shmem_hdr_t *shmem_hdr;
404 
405  am = vlibapi_get_main ();
406  shmem_hdr = am->shmem_hdr;
407 
408  rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp));
409  clib_memset (rmp, 0, sizeof (*rmp));
410  rmp->_vl_msg_id = ntohs (VL_API_MEMCLNT_KEEPALIVE_REPLY);
411  rmp->context = mp->context;
412  vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & rmp);
413 }
414 
415 /*
416  * To avoid filling the API trace buffer with boring messages,
417  * don't trace memclnt_keepalive[_reply] msgs
418  */
419 
420 #define foreach_vlib_api_msg \
421 _(MEMCLNT_CREATE, memclnt_create, 1) \
422 _(MEMCLNT_DELETE, memclnt_delete, 1) \
423 _(MEMCLNT_KEEPALIVE, memclnt_keepalive, 0) \
424 _(MEMCLNT_KEEPALIVE_REPLY, memclnt_keepalive_reply, 0)
425 
426 /*
427  * memory_api_init
428  */
429 int
430 vl_mem_api_init (const char *region_name)
431 {
432  int rv;
435  vl_msg_api_msg_config_t *c = &cfg;
436  vl_shmem_hdr_t *shm;
438 
439  clib_memset (c, 0, sizeof (*c));
440 
441  if ((rv = vl_map_shmem (region_name, 1 /* is_vlib */ )) < 0)
442  return rv;
443 
444 #define _(N,n,t) do { \
445  c->id = VL_API_##N; \
446  c->name = #n; \
447  c->handler = vl_api_##n##_t_handler; \
448  c->cleanup = vl_noop_handler; \
449  c->endian = vl_api_##n##_t_endian; \
450  c->print = vl_api_##n##_t_print; \
451  c->size = sizeof(vl_api_##n##_t); \
452  c->traced = t; /* trace, so these msgs print */ \
453  c->replay = 0; /* don't replay client create/delete msgs */ \
454  c->message_bounce = 0; /* don't bounce this message */ \
455  vl_msg_api_config(c);} while (0);
456 
458 #undef _
459 
460  /*
461  * special-case freeing of memclnt_delete messages, so we can
462  * simply munmap pairwise / private API segments...
463  */
464  am->message_bounce[VL_API_MEMCLNT_DELETE] = 1;
465  am->is_mp_safe[VL_API_MEMCLNT_KEEPALIVE_REPLY] = 1;
466  am->is_mp_safe[VL_API_MEMCLNT_KEEPALIVE] = 1;
467 
469 
470  shm = am->shmem_hdr;
471  ASSERT (shm && shm->vl_input_queue);
472 
473  /* Make a note so we can always find the primary region easily */
474  am->vlib_primary_rp = am->vlib_rp;
475 
476  return 0;
477 }
478 
479 clib_error_t *
481 {
483  int rv;
484 
485  if ((rv = vl_mem_api_init (am->region_name)) < 0)
486  {
487  return clib_error_return (0, "vl_mem_api_init (%s) failed",
488  am->region_name);
489  }
490  return 0;
491 }
492 
493 static void
495 {
497  svm_queue_t *q;
499 
500  q = regp->vl_input_queue;
501 
502  /*
503  * If the queue head is moving, assume that the client is processing
504  * messages and skip the ping. This heuristic may fail if the queue
505  * is in the same position as last time, net of wrapping; in which
506  * case, the client will receive a keepalive.
507  */
508  if (regp->last_queue_head != q->head)
509  {
510  regp->last_heard = now;
511  regp->unanswered_pings = 0;
512  regp->last_queue_head = q->head;
513  return;
514  }
515 
516  /*
517  * push/pop shared memory segment, so this routine
518  * will work with "normal" as well as "private segment"
519  * memory clients..
520  */
521 
522  mp = vl_mem_api_alloc_as_if_client_w_reg (regp, sizeof (*mp));
523  clib_memset (mp, 0, sizeof (*mp));
524  mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MEMCLNT_KEEPALIVE);
525  mp->context = mp->client_index =
528  am->shmem_hdr->application_restarts);
529 
530  regp->unanswered_pings++;
531 
532  /* Failure-to-send due to a stuffed queue is absolutely expected */
533  if (svm_queue_add (q, (u8 *) & mp, 1 /* nowait */ ))
534  vl_msg_api_free_w_region (regp->vlib_rp, mp);
535 }
536 
537 static void
539  vl_api_registration_t ** regpp,
540  u32 ** dead_indices,
541  u32 ** confused_indices)
542 {
543  vl_api_registration_t *regp = *regpp;
544  if (regp)
545  {
546  /* If we haven't heard from this client recently... */
547  if (regp->last_heard < (now - 10.0))
548  {
549  if (regp->unanswered_pings == 2)
550  {
551  svm_queue_t *q;
552  q = regp->vl_input_queue;
553  if (kill (q->consumer_pid, 0) >= 0)
554  {
555  clib_warning ("REAPER: lazy binary API client '%s'",
556  regp->name);
557  regp->unanswered_pings = 0;
558  regp->last_heard = now;
559  }
560  else
561  {
562  clib_warning ("REAPER: binary API client '%s' died",
563  regp->name);
564  vec_add1 (*dead_indices, regpp - am->vl_clients);
565  }
566  }
567  else
568  send_memclnt_keepalive (regp, now);
569  }
570  else
571  regp->unanswered_pings = 0;
572  }
573  else
574  {
575  clib_warning ("NULL client registration index %d",
576  regpp - am->vl_clients);
577  vec_add1 (*confused_indices, regpp - am->vl_clients);
578  }
579 }
580 
581 void
583 {
584  vl_api_registration_t **regpp;
585  static u32 *dead_indices;
586  static u32 *confused_indices;
587 
588  vec_reset_length (dead_indices);
589  vec_reset_length (confused_indices);
590 
591  /* *INDENT-OFF* */
592  pool_foreach (regpp, am->vl_clients) {
593  vl_mem_send_client_keepalive_w_reg (am, now, regpp, &dead_indices,
594  &confused_indices);
595  }
596  /* *INDENT-ON* */
597 
598  /* This should "never happen," but if it does, fix it... */
599  if (PREDICT_FALSE (vec_len (confused_indices) > 0))
600  {
601  int i;
602  for (i = 0; i < vec_len (confused_indices); i++)
603  {
604  pool_put_index (am->vl_clients, confused_indices[i]);
605  }
606  }
607 
608  if (PREDICT_FALSE (vec_len (dead_indices) > 0))
609  {
610  int i;
611  void *oldheap;
612 
613  /* Allow the application to clean up its registrations */
614  for (i = 0; i < vec_len (dead_indices); i++)
615  {
616  regpp = pool_elt_at_index (am->vl_clients, dead_indices[i]);
617  if (regpp)
618  {
619  u32 handle;
620 
622  (dead_indices[i], shm->application_restarts);
624  }
625  }
626 
627  oldheap = vl_msg_push_heap ();
628 
629  for (i = 0; i < vec_len (dead_indices); i++)
630  {
631  regpp = pool_elt_at_index (am->vl_clients, dead_indices[i]);
632  if (regpp)
633  {
634  /* Is this a pairwise SVM segment? */
635  if ((*regpp)->vlib_rp != am->vlib_rp)
636  {
637  int i;
638  svm_region_t *dead_rp = (*regpp)->vlib_rp;
639  /* Note: account for the memfd header page */
640  uword virtual_base = dead_rp->virtual_base - MMAP_PAGESIZE;
641  uword virtual_size = dead_rp->virtual_size + MMAP_PAGESIZE;
642 
643  /* For horizontal scaling, add a hash table... */
644  for (i = 0; i < vec_len (am->vlib_private_rps); i++)
645  if (am->vlib_private_rps[i] == dead_rp)
646  {
647  vec_delete (am->vlib_private_rps, 1, i);
648  goto found;
649  }
650  svm_pop_heap (oldheap);
651  clib_warning ("private rp %llx AWOL", dead_rp);
652  oldheap = svm_push_data_heap (am->vlib_rp);
653 
654  found:
655  /* Kill it, accounting for the memfd header page */
656  svm_pop_heap (oldheap);
657  if (munmap ((void *) virtual_base, virtual_size) < 0)
658  clib_unix_warning ("munmap");
659  /* Reset the queue-length-address cache */
661  oldheap = svm_push_data_heap (am->vlib_rp);
662  }
663  else
664  {
665  /* Poison the old registration */
666  clib_memset (*regpp, 0xF3, sizeof (**regpp));
667  clib_mem_free (*regpp);
668  }
669  /* no dangling references, please */
670  *regpp = 0;
671  }
672  else
673  {
674  svm_pop_heap (oldheap);
675  clib_warning ("Duplicate free, client index %d",
676  regpp - am->vl_clients);
677  oldheap = svm_push_data_heap (am->vlib_rp);
678  }
679  }
680 
682 
683  vl_msg_pop_heap (oldheap);
684  for (i = 0; i < vec_len (dead_indices); i++)
685  pool_put_index (am->vl_clients, dead_indices[i]);
686  }
687 }
688 
689 static inline int
692  u8 is_private)
693 {
694  svm_queue_t *q;
695  uword mp;
696 
697  q = ((vl_shmem_hdr_t *) (void *) vlib_rp->user_ctx)->vl_input_queue;
698 
699  if (!svm_queue_sub2 (q, (u8 *) & mp))
700  {
701  VL_MSG_API_UNPOISON ((void *) mp);
702  vl_msg_api_handler_with_vm_node (am, vlib_rp, (void *) mp, vm, node,
703  is_private);
704  return 0;
705  }
706  return -1;
707 }
708 
709 int
711 {
713  return void_mem_api_handle_msg_i (am, am->vlib_rp, vm, node,
714  0 /* is_private */ );
715 }
716 
717 int
719 {
721  int i;
722  uword *tmp, mp;
723 
724  /*
725  * Swap pending and processing vectors, then process the RPCs
726  * Avoid deadlock conditions by construction.
727  */
734 
735  /*
736  * RPCs are used to reflect function calls to thread 0
737  * when the underlying code is not thread-safe.
738  *
739  * Grabbing the thread barrier across a set of RPCs
740  * greatly increases efficiency, and avoids
741  * running afoul of the barrier sync holddown timer.
742  * The barrier sync code supports recursive locking.
743  *
744  * We really need to rewrite RPC-based code...
745  */
747  {
749  for (i = 0; i < vec_len (vm->processing_rpc_requests); i++)
750  {
752  vl_msg_api_handler_with_vm_node (am, am->vlib_rp, (void *) mp, vm,
753  node, 0 /* is_private */ );
754  }
756  }
757 
758  return 0;
759 }
760 
761 int
763  u32 reg_index)
764 {
766  return void_mem_api_handle_msg_i (am, am->vlib_private_rps[reg_index], vm,
767  node, 1 /* is_private */ );
768 }
769 
772 {
773  vl_api_registration_t **regpp;
774  vl_api_registration_t *regp;
776  vl_shmem_hdr_t *shmem_hdr;
777  u32 index;
778 
780  regpp = am->vl_clients + index;
781 
782  if (pool_is_free (am->vl_clients, regpp))
783  {
785  return 0;
786  }
787  regp = *regpp;
788 
789  shmem_hdr = (vl_shmem_hdr_t *) regp->shmem_hdr;
790  if (!vl_msg_api_handle_is_valid (handle, shmem_hdr->application_restarts))
791  {
793  return 0;
794  }
795 
796  return (regp);
797 }
798 
799 svm_queue_t *
801 {
802  vl_api_registration_t *regp;
804 
805  /* Special case: vlib trying to send itself a message */
806  if (index == (u32) ~ 0)
807  return (am->shmem_hdr->vl_input_queue);
808 
810  if (!regp)
811  return 0;
812  return (regp->vl_input_queue);
813 }
814 
815 static clib_error_t *
817 {
818  atexit (vl_unmap_shmem);
819  return 0;
820 }
821 
823 
824 u8 *
825 format_api_message_rings (u8 * s, va_list * args)
826 {
827  api_main_t *am = va_arg (*args, api_main_t *);
828  vl_shmem_hdr_t *shmem_hdr = va_arg (*args, vl_shmem_hdr_t *);
829  int main_segment = va_arg (*args, int);
830  ring_alloc_t *ap;
831  int i;
832 
833  if (shmem_hdr == 0)
834  return format (s, "%8s %8s %8s %8s %8s\n",
835  "Owner", "Size", "Nitems", "Hits", "Misses");
836 
837  ap = shmem_hdr->vl_rings;
838 
839  for (i = 0; i < vec_len (shmem_hdr->vl_rings); i++)
840  {
841  s = format (s, "%8s %8d %8d %8d %8d\n",
842  "vlib", ap->size, ap->nitems, ap->hits, ap->misses);
843  ap++;
844  }
845 
846  ap = shmem_hdr->client_rings;
847 
848  for (i = 0; i < vec_len (shmem_hdr->client_rings); i++)
849  {
850  s = format (s, "%8s %8d %8d %8d %8d\n",
851  "clnt", ap->size, ap->nitems, ap->hits, ap->misses);
852  ap++;
853  }
854 
855  if (main_segment)
856  {
857  s = format (s, "%d ring miss fallback allocations\n", am->ring_misses);
858  s = format
859  (s,
860  "%d application restarts, %d reclaimed msgs, %d garbage collects\n",
861  shmem_hdr->application_restarts, shmem_hdr->restart_reclaims,
862  shmem_hdr->garbage_collects);
863  }
864  return s;
865 }
866 
867 static clib_error_t *
869  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
870 {
871  int i;
872  vl_shmem_hdr_t *shmem_hdr;
874 
875  /* First, dump the primary region rings.. */
876 
877  if (am->vlib_primary_rp == 0 || am->vlib_primary_rp->user_ctx == 0)
878  {
879  vlib_cli_output (vm, "Shared memory segment not initialized...\n");
880  return 0;
881  }
882 
883  shmem_hdr = (void *) am->vlib_primary_rp->user_ctx;
884 
885  vlib_cli_output (vm, "Main API segment rings:");
886 
888  0 /* print header */ , 0 /* notused */ );
889 
891  shmem_hdr, 1 /* main segment */ );
892 
893  for (i = 0; i < vec_len (am->vlib_private_rps); i++)
894  {
895  svm_region_t *vlib_rp = am->vlib_private_rps[i];
896  shmem_hdr = (void *) vlib_rp->user_ctx;
897  vl_api_registration_t **regpp;
898  vl_api_registration_t *regp = 0;
899 
900  /* For horizontal scaling, add a hash table... */
901  /* *INDENT-OFF* */
902  pool_foreach (regpp, am->vl_clients)
903  {
904  regp = *regpp;
905  if (regp && regp->vlib_rp == vlib_rp)
906  {
907  vlib_cli_output (vm, "%s segment rings:", regp->name);
908  goto found;
909  }
910  }
911  vlib_cli_output (vm, "regp %llx not found?", regp);
912  continue;
913  /* *INDENT-ON* */
914  found:
916  0 /* print header */ , 0 /* notused */ );
918  shmem_hdr, 0 /* main segment */ );
919  }
920 
921  return 0;
922 }
923 
924 /*?
925  * Display binary api message allocation ring statistics
926 ?*/
927 /* *INDENT-OFF* */
929 {
930  .path = "show api ring-stats",
931  .short_help = "Message ring statistics",
932  .function = vl_api_ring_command,
933 };
934 /* *INDENT-ON* */
935 
936 clib_error_t *
938 {
940  svm_map_region_args_t _a, *a = &_a;
941  u8 *remove_path1, *remove_path2;
942  void vlibsocket_reference (void);
943 
945 
946  /*
947  * By popular request / to avoid support fires, remove any old api segment
948  * files Right Here.
949  */
950  if (am->root_path == 0)
951  {
952  remove_path1 = format (0, "/dev/shm/global_vm%c", 0);
953  remove_path2 = format (0, "/dev/shm/vpe-api%c", 0);
954  }
955  else
956  {
957  remove_path1 = format (0, "/dev/shm/%s-global_vm%c", am->root_path, 0);
958  remove_path2 = format (0, "/dev/shm/%s-vpe-api%c", am->root_path, 0);
959  }
960 
961  (void) unlink ((char *) remove_path1);
962  (void) unlink ((char *) remove_path2);
963 
964  vec_free (remove_path1);
965  vec_free (remove_path2);
966 
967  clib_memset (a, 0, sizeof (*a));
968  a->root_path = am->root_path;
969  a->name = SVM_GLOBAL_REGION_NAME;
970  a->baseva = (am->global_baseva != 0) ?
971  am->global_baseva : +svm_get_global_region_base_va ();
972  a->size = (am->global_size != 0) ? am->global_size : SVM_GLOBAL_REGION_SIZE;
973  a->flags = SVM_FLAGS_NODATA;
974  a->uid = am->api_uid;
975  a->gid = am->api_gid;
976  a->pvt_heap_size =
977  (am->global_pvt_heap_size !=
978  0) ? am->global_pvt_heap_size : SVM_PVT_MHEAP_SIZE;
979 
981 
982  return 0;
983 }
984 
985 void
987 {
989  am->region_name = name;
990 }
991 
992 /*
993  * fd.io coding-style-patch-verification: ON
994  *
995  * Local Variables:
996  * eval: (c-set-style "gnu")
997  * End:
998  */
vec_reset_length
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
Definition: vec_bootstrap.h:194
vlib.h
vl_msg_api_barrier_release
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:432
tmp
u32 * tmp
Definition: interface_output.c:1096
vl_msg_api_handle_get_index
static u32 vl_msg_api_handle_get_index(u32 index)
Definition: memory_api.h:48
SVM_GLOBAL_REGION_SIZE
#define SVM_GLOBAL_REGION_SIZE
Definition: svm_common.h:101
vl_print
#define vl_print(handle,...)
Definition: memory_api.c:31
vl_api_client_index_to_registration
static vl_api_registration_t * vl_api_client_index_to_registration(u32 index)
Definition: api.h:79
ring_alloc_::hits
u32 hits
Definition: memory_shared.h:40
vl_shmem_hdr_::application_restarts
u32 application_restarts
Definition: memory_shared.h:95
api.h
ntohs
#define ntohs(x)
Definition: af_xdp.bpf.c:29
vl_mem_api_alloc_as_if_client_w_reg
void * vl_mem_api_alloc_as_if_client_w_reg(vl_api_registration_t *reg, int nbytes)
Definition: memory_shared.c:262
clib_spinlock_lock_if_init
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
Definition: lock.h:106
vl_mem_api_handle_msg_private
int vl_mem_api_handle_msg_private(vlib_main_t *vm, vlib_node_runtime_t *node, u32 reg_index)
Definition: memory_api.c:762
vl_map_shmem
int vl_map_shmem(const char *region_name, int is_vlib)
Definition: memory_shared.c:534
pointer_to_uword
static uword pointer_to_uword(const void *p)
Definition: types.h:131
vl_api_memclnt_create_reply_t::index
u32 index
Definition: memclnt.api:45
pool_elt_at_index
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:549
vl_api_memclnt_keepalive_reply_t_handler
void vl_api_memclnt_keepalive_reply_t_handler(vl_api_memclnt_keepalive_reply_t *mp)
client answered a ping, stave off the grim reaper...
Definition: memory_api.c:379
name
string name[64]
Definition: fib.api:25
vl_msg_api_handle_from_index_and_epoch
static u32 vl_msg_api_handle_from_index_and_epoch(u32 index, u32 epoch)
Definition: memory_api.h:54
SVM_FLAGS_NODATA
#define SVM_FLAGS_NODATA
Definition: svm_common.h:30
vlib_main_t::pending_rpc_lock
clib_spinlock_t pending_rpc_lock
Definition: main.h:264
clib_mem_free
static void clib_mem_free(void *p)
Definition: mem.h:314
node
vlib_main_t vlib_node_runtime_t * node
Definition: nat44_ei.c:3047
vl_api_memclnt_delete_t
Definition: memclnt.api:53
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
vlib_cli_command_t::path
char * path
Definition: cli.h:96
svm_queue_t
struct _svm_queue svm_queue_t
api_main_t::reaper_function_registrations
_vl_msg_api_function_list_elt_t * reaper_function_registrations
List of API client reaper functions.
Definition: api_common.h:369
vl_msg_api_msg_config_t
Message configuration definition.
Definition: api_common.h:122
vl_api_registration_::registration_type
vl_registration_type_t registration_type
type
Definition: api_common.h:49
am
app_main_t * am
Definition: application.c:489
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
api.h
vl_api_registration_::vl_input_queue
svm_queue_t * vl_input_queue
shared memory only: pointer to client input queue
Definition: api_common.h:63
vec_delete
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:875
vl_api_memclnt_create_t::name
string name[64]
Definition: memclnt.api:37
vl_api_ring_command
static clib_error_t * vl_api_ring_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_api.c:868
vl_msg_api_handle_is_valid
static u8 vl_msg_api_handle_is_valid(u32 handle, u32 restarts)
Definition: memory_api.h:64
vl_api_memclnt_create_reply_t::context
u32 context
Definition: memclnt.api:42
clib_error_report
#define clib_error_report(e)
Definition: error.h:113
unformat_input_t
struct _unformat_input_t unformat_input_t
vlib_process_signal_event
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:1019
pool_put_index
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:337
vlib_main_t::queue_signal_pending
volatile u32 queue_signal_pending
Definition: main.h:220
vl_shmem_hdr_
Definition: memory_shared.h:76
vl_msg_api_alloc_as_if_client
void * vl_msg_api_alloc_as_if_client(int nbytes)
Definition: memory_shared.c:236
clib_unix_warning
#define clib_unix_warning(format, args...)
Definition: error.h:68
error
Definition: cJSON.c:88
vl_api_memclnt_create_reply_t
Definition: memclnt.api:41
vl_api_memclnt_create_reply_t::message_table
u64 message_table
Definition: memclnt.api:46
vl_api_memclnt_create_t
Definition: memclnt.api:33
vl_api_memclnt_delete_reply_t
Definition: memclnt.api:59
svm_region_init_args
void svm_region_init_args(svm_map_region_args_t *a)
Definition: svm.c:875
VL_MSG_API_UNPOISON
static CLIB_NOSANITIZE_ADDR void VL_MSG_API_UNPOISON(const void *a)
Definition: api_common.h:149
vlib_main_t::processing_rpc_requests
uword * processing_rpc_requests
Definition: main.h:263
vl_api_memclnt_create_t::context
u32 context
Definition: memclnt.api:34
vl_shmem_hdr_::client_rings
ring_alloc_t * client_rings
Definition: memory_shared.h:92
format_api_message_rings
u8 * format_api_message_rings(u8 *s, va_list *args)
Definition: memory_api.c:825
pool_foreach
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
vl_api_registration_::last_queue_head
int last_queue_head
Definition: api_common.h:58
svm_queue_free
void svm_queue_free(svm_queue_t *q)
Definition: queue.c:91
vl_set_memory_region_name
void vl_set_memory_region_name(const char *name)
Definition: memory_api.c:986
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
vl_api_client_index_to_input_queue
svm_queue_t * vl_api_client_index_to_input_queue(u32 index)
Definition: memory_api.c:800
vl_api_registration_::unanswered_pings
int unanswered_pings
Definition: api_common.h:59
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
vl_mem_api_handle_rpc
int vl_mem_api_handle_rpc(vlib_main_t *vm, vlib_node_runtime_t *node)
Definition: memory_api.c:718
vl_mem_api_handle_msg_main
int vl_mem_api_handle_msg_main(vlib_main_t *vm, vlib_node_runtime_t *node)
Definition: memory_api.c:710
vl_api_memclnt_keepalive_t_handler
static void vl_api_memclnt_keepalive_t_handler(vl_api_memclnt_keepalive_t *mp)
We can send ourselves these messages if someone uses the builtin binary api test tool....
Definition: memory_api.c:399
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
vlib_get_thread_index
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:187
vl_api_registration_
An API client registration, only in vpp/vlib.
Definition: api_common.h:47
vl_api_memclnt_delete_reply_t::handle
u64 handle
Definition: memclnt.api:61
map_api_segment_init
clib_error_t * map_api_segment_init(vlib_main_t *vm)
Definition: memory_api.c:480
c
svmdb_client_t * c
Definition: vpp_get_metrics.c:48
pool_is_free
#define pool_is_free(P, E)
Use free bitmap to query whether given element is free.
Definition: pool.h:294
vl_shmem_hdr_::vl_input_queue
svm_queue_t * vl_input_queue
Definition: memory_shared.h:84
uword
u64 uword
Definition: types.h:112
memclnt_queue_callback
static void memclnt_queue_callback(vlib_main_t *vm)
Definition: memory_api.c:64
if
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
svm_pop_heap
static void svm_pop_heap(void *oldheap)
Definition: svm.h:94
vl_api_registration_::clib_file_index
u32 clib_file_index
Socket only: file index.
Definition: api_common.h:68
vlibsocket_reference
void vlibsocket_reference()
Definition: socket_api.c:874
vlibapi_get_main
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:390
vl_api_memclnt_create_reply_t::handle
u64 handle
Definition: memclnt.api:44
vl_mem_send_client_keepalive_w_reg
static void vl_mem_send_client_keepalive_w_reg(api_main_t *am, f64 now, vl_api_registration_t **regpp, u32 **dead_indices, u32 **confused_indices)
Definition: memory_api.c:538
f64
double f64
Definition: types.h:142
vl_api_memclnt_keepalive_t::client_index
u32 client_index
Definition: memclnt.api:209
vl_api_serialize_message_table
u8 * vl_api_serialize_message_table(api_main_t *am, u8 *vector)
Definition: api_shared.c:204
pool_get
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
VLIB_CLI_COMMAND
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
memory_api.h
vlib_main_t::pending_rpc_requests
uword * pending_rpc_requests
Definition: main.h:262
vl_unmap_shmem
void vl_unmap_shmem(void)
Definition: memory_shared.c:741
vlib_main_t::api_queue_nonempty
volatile u32 api_queue_nonempty
Definition: main.h:221
svm_region_::virtual_size
uword virtual_size
Definition: svm_common.h:44
vlib_cli_output
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
void_mem_api_handle_msg_i
static int void_mem_api_handle_msg_i(api_main_t *am, svm_region_t *vlib_rp, vlib_main_t *vm, vlib_node_runtime_t *node, u8 is_private)
Definition: memory_api.c:690
MMAP_PAGESIZE
#define MMAP_PAGESIZE
Definition: ssvm.h:42
api_main_t
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:228
setup_memclnt_exit
static clib_error_t * setup_memclnt_exit(vlib_main_t *vm)
Definition: memory_api.c:816
svm_queue_sub2
int svm_queue_sub2(svm_queue_t *q, u8 *elem)
Definition: queue.c:434
vl_api_memclnt_keepalive_t::context
u32 context
Definition: memclnt.api:210
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
index
u32 index
Definition: flow_types.api:221
VL_API_EPOCH_MASK
#define VL_API_EPOCH_MASK
Definition: memory_shared.h:108
vl_api_memclnt_delete_reply_t::response
i32 response
Definition: memclnt.api:60
vl_api_registration_::shmem_hdr
void * shmem_hdr
Definition: api_common.h:65
vl_msg_api_free_w_region
void vl_msg_api_free_w_region(svm_region_t *vlib_rp, void *a)
Definition: memory_shared.c:269
foreach_vlib_api_msg
#define foreach_vlib_api_msg
Definition: memory_api.c:420
svm_queue_add
int svm_queue_add(svm_queue_t *q, u8 *elem, int nowait)
Definition: queue.c:260
vl_api_memclnt_delete_t::do_cleanup
bool do_cleanup
Definition: memclnt.api:56
vl_msg_api_free
void vl_msg_api_free(void *)
Definition: memory_shared.c:311
svm_get_global_region_base_va
u64 svm_get_global_region_base_va()
Definition: svm.c:61
format
description fragment has unexpected format
Definition: map.api:433
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
vl_mem_api_init
int vl_mem_api_init(const char *region_name)
Definition: memory_api.c:430
vl_api_memclnt_delete_t::index
u32 index
Definition: memclnt.api:54
QUEUE_SIGNAL_EVENT
@ QUEUE_SIGNAL_EVENT
Definition: api.h:133
svm_client_scan_this_region_nolock
void svm_client_scan_this_region_nolock(svm_region_t *rp)
Definition: svm.c:1223
vl_msg_api_handle_get_epoch
static u32 vl_msg_api_handle_get_epoch(u32 index)
Definition: memory_api.h:42
vl_mem_api_dead_client_scan
void vl_mem_api_dead_client_scan(api_main_t *am, vl_shmem_hdr_t *shm, f64 now)
Definition: memory_api.c:582
vl_msg_api_increment_missing_client_counter
void vl_msg_api_increment_missing_client_counter(void)
Definition: api_shared.c:55
vl_api_memclnt_create_t_print
static void * vl_api_memclnt_create_t_print(vl_api_memclnt_create_t *a, void *handle)
Definition: memory_api.c:42
u32
unsigned int u32
Definition: types.h:88
svm_region_::user_ctx
volatile void * user_ctx
Definition: svm_common.h:48
vl_msg_push_heap
void * vl_msg_push_heap(void)
Definition: cli.c:745
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
cli_show_api_ring_command
static vlib_cli_command_t cli_show_api_ring_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_ring_command)
Definition: memory_api.c:928
vl_shmem_hdr_::restart_reclaims
u32 restart_reclaims
Definition: memory_shared.h:98
svm_region_::virtual_base
uword virtual_base
Definition: svm_common.h:43
ring_alloc_::size
u16 size
Definition: memory_shared.h:38
vl_api_memclnt_keepalive_t
Definition: memclnt.api:207
vl_shmem_hdr_::vl_rings
ring_alloc_t * vl_rings
Definition: memory_shared.h:89
vlibmemory_init
clib_error_t * vlibmemory_init(vlib_main_t *vm)
Definition: memory_api.c:937
vl_api_registration_::vlib_rp
svm_region_t * vlib_rp
Definition: api_common.h:64
now
f64 now
Definition: nat44_ei_out2in.c:710
vlib_set_queue_signal_callback
static void vlib_set_queue_signal_callback(vlib_main_t *vm, void(*fp)(vlib_main_t *))
Definition: main.h:458
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
vl_shmem_hdr_::garbage_collects
u32 garbage_collects
Definition: memory_shared.h:101
vlib_get_main
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:38
svm_region_
Definition: svm_common.h:35
SVM_GLOBAL_REGION_NAME
#define SVM_GLOBAL_REGION_NAME
Definition: svm_common.h:102
u8
unsigned char u8
Definition: types.h:56
vl_api_call_reaper_functions
void vl_api_call_reaper_functions(u32 client_index)
Definition: memory_api.c:241
clib_error_t
Definition: clib_error.h:21
a
a
Definition: bitmap.h:525
vl_msg_api_send_shmem
void vl_msg_api_send_shmem(svm_queue_t *q, u8 *elem)
Definition: memory_shared.c:753
vl_api_memclnt_create_t::input_queue
u64 input_queue
Definition: memclnt.api:36
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
vl_api_memclnt_delete_t_print
static void * vl_api_memclnt_delete_t_print(vl_api_memclnt_delete_t *a, void *handle)
Definition: memory_api.c:53
vl_api_memclnt_delete_t::handle
u64 handle
Definition: memclnt.api:55
i
int i
Definition: flowhash_template.h:376
VL_MSG_API_SVM_QUEUE_UNPOISON
static CLIB_NOSANITIZE_ADDR void VL_MSG_API_SVM_QUEUE_UNPOISON(const svm_queue_t *q)
Definition: api_common.h:156
SVM_PVT_MHEAP_SIZE
#define SVM_PVT_MHEAP_SIZE
Definition: svm_common.h:33
clib_warning
#define clib_warning(format, args...)
Definition: error.h:59
send_memclnt_keepalive
static void send_memclnt_keepalive(vl_api_registration_t *regp, f64 now)
Definition: memory_api.c:494
rv
int __clib_unused rv
Definition: application.c:491
vl_memory_api_h.h
REGISTRATION_TYPE_SHMEM
@ REGISTRATION_TYPE_SHMEM
Shared memory connection.
Definition: api_common.h:39
vlib_time_now
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:327
vl_api_registration_::name
u8 * name
Client name.
Definition: api_common.h:54
vl_api_registration_::last_heard
f64 last_heard
Definition: api_common.h:57
vlib_node_runtime_t
Definition: node.h:454
clib_spinlock_unlock_if_init
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:129
vl_msg_pop_heap
void vl_msg_pop_heap(void *oldheap)
Definition: cli.c:752
vl_mem_api_client_index_to_registration
vl_api_registration_t * vl_mem_api_client_index_to_registration(u32 handle)
Definition: memory_api.c:771
vl_api_memclnt_create_reply_t::response
i32 response
Definition: memclnt.api:43
vl_api_clnt_node
vlib_node_registration_t vl_api_clnt_node
(constructor) VLIB_REGISTER_NODE (vl_api_clnt_node)
Definition: vlib_api.c:434
vlib_cli_command_t
Definition: cli.h:92
PREDICT_TRUE
#define PREDICT_TRUE(x)
Definition: clib.h:125
svm_push_data_heap
static void * svm_push_data_heap(svm_region_t *rp)
Definition: svm.h:86
vl_api_memclnt_create_t_handler
void vl_api_memclnt_create_t_handler(vl_api_memclnt_create_t *mp)
Definition: memory_api.c:160
vl_memory_msg_enum.h
vl_msg_api_barrier_sync
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:427
ring_alloc_
Definition: memory_shared.h:35
clib_mem_alloc
static void * clib_mem_alloc(uword size)
Definition: mem.h:256
vl_msg_api_handler_with_vm_node
void vl_msg_api_handler_with_vm_node(api_main_t *am, svm_region_t *vlib_rp, void *the_msg, vlib_main_t *vm, vlib_node_runtime_t *node, u8 is_private)
Definition: api_shared.c:557
vl_api_memclnt_delete_t_handler
void vl_api_memclnt_delete_t_handler(vl_api_memclnt_delete_t *mp)
Definition: memory_api.c:260
ring_alloc_::nitems
u16 nitems
Definition: memory_shared.h:39
vl_api_queue_cursizes
volatile int ** vl_api_queue_cursizes
Definition: memory_api.c:61
vl_api_memclnt_create_internal
u32 vl_api_memclnt_create_internal(char *name, svm_queue_t *q)
Definition: memory_api.c:126
vl_api_registration_::vl_api_registration_pool_index
u32 vl_api_registration_pool_index
Index in VLIB's brain (not shared memory).
Definition: api_common.h:52
ring_alloc_::misses
u32 misses
Definition: memory_shared.h:41
vl_msg_api_alloc
void * vl_msg_api_alloc(int nbytes)
Definition: memory_shared.c:199
svm_map_region_args_
Definition: svm_common.h:66