LCOV - code coverage report
Current view: top level - vlibapi - memory_shared.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 195 343 56.9 %
Date: 2023-10-26 01:39:38 Functions: 18 30 60.0 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * memclnt_shared.c - API message handling, common code for both clients
       4             :  * and the vlib process itself.
       5             :  *
       6             :  *
       7             :  * Copyright (c) 2009 Cisco and/or its affiliates.
       8             :  * Licensed under the Apache License, Version 2.0 (the "License");
       9             :  * you may not use this file except in compliance with the License.
      10             :  * You may obtain a copy of the License at:
      11             :  *
      12             :  *     http://www.apache.org/licenses/LICENSE-2.0
      13             :  *
      14             :  * Unless required by applicable law or agreed to in writing, software
      15             :  * distributed under the License is distributed on an "AS IS" BASIS,
      16             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      17             :  * See the License for the specific language governing permissions and
      18             :  * limitations under the License.
      19             :  *------------------------------------------------------------------
      20             :  */
      21             : 
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <stddef.h>
      25             : #include <string.h>
      26             : #include <unistd.h>
      27             : #include <signal.h>
      28             : 
      29             : #include <vppinfra/format.h>
      30             : #include <vppinfra/byte_order.h>
      31             : #include <vppinfra/error.h>
      32             : #include <vppinfra/elog.h>
      33             : #include <svm/queue.h>
      34             : #include <vlib/vlib.h>
      35             : #include <vlib/unix/unix.h>
      36             : #include <vlibmemory/memory_api.h>
      37             : #include <vlibmemory/vl_memory_msg_enum.h>
      38             : #include <vlibapi/api_common.h>
      39             : 
      40             : #define vl_typedefs
      41             : #include <vlibmemory/vl_memory_api_h.h>
      42             : #undef vl_typedefs
      43             : 
      44             : #define DEBUG_MESSAGE_BUFFER_OVERRUN 0
      45             : 
      46             : __clib_nosanitize_addr static inline void *
      47      763594 : vl_msg_api_alloc_internal (svm_region_t *vlib_rp, int nbytes, int pool,
      48             :                            int may_return_null)
      49             : {
      50             :   int i;
      51             :   msgbuf_t *rv;
      52             :   ring_alloc_t *ap;
      53             :   svm_queue_t *q;
      54             :   void *oldheap;
      55             :   vl_shmem_hdr_t *shmem_hdr;
      56      763594 :   api_main_t *am = vlibapi_get_main ();
      57             : 
      58      763594 :   shmem_hdr = (void *) vlib_rp->user_ctx;
      59             : 
      60             : #if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
      61             :   nbytes += 4;
      62             : #endif
      63             : 
      64      763594 :   ASSERT (pool == 0 || vlib_get_thread_index () == 0);
      65             : 
      66      763594 :   if (shmem_hdr == 0)
      67             :     {
      68           0 :       clib_warning ("shared memory header NULL");
      69           0 :       return 0;
      70             :     }
      71             : 
      72             :   /* account for the msgbuf_t header */
      73      763594 :   nbytes += sizeof (msgbuf_t);
      74             : 
      75      763594 :   if (shmem_hdr->vl_rings == 0)
      76             :     {
      77           0 :       clib_warning ("vl_rings NULL");
      78           0 :       ASSERT (0);
      79           0 :       abort ();
      80             :     }
      81             : 
      82      763594 :   if (shmem_hdr->client_rings == 0)
      83             :     {
      84           0 :       clib_warning ("client_rings NULL");
      85           0 :       ASSERT (0);
      86           0 :       abort ();
      87             :     }
      88             : 
      89      763594 :   ap = pool ? shmem_hdr->vl_rings : shmem_hdr->client_rings;
      90     1152270 :   for (i = 0; i < vec_len (ap); i++)
      91             :     {
      92             :       /* Too big? */
      93     1124580 :       if (nbytes > ap[i].size)
      94             :         {
      95      388679 :           continue;
      96             :         }
      97             : 
      98      735896 :       q = ap[i].rp;
      99      735896 :       if (pool == 0)
     100             :         {
     101       63059 :           pthread_mutex_lock (&q->mutex);
     102             :         }
     103      735896 :       rv = (msgbuf_t *) (&q->data[0] + q->head * q->elsize);
     104             :       /*
     105             :        * Is this item still in use?
     106             :        */
     107      735896 :       if (rv->q)
     108             :         {
     109           0 :           u32 now = (u32) time (0);
     110             : 
     111           0 :           if (PREDICT_TRUE (rv->gc_mark_timestamp == 0))
     112           0 :             rv->gc_mark_timestamp = now;
     113             :           else
     114             :             {
     115           0 :               if (now - rv->gc_mark_timestamp > 10)
     116             :                 {
     117             :                   if (CLIB_DEBUG > 0)
     118             :                     {
     119             :                       u16 *msg_idp, msg_id;
     120             :                       vl_api_msg_data_t *m;
     121           0 :                       clib_warning
     122             :                         ("garbage collect pool %d ring %d index %d", pool, i,
     123             :                          q->head);
     124           0 :                       msg_idp = (u16 *) (rv->data);
     125           0 :                       msg_id = clib_net_to_host_u16 (*msg_idp);
     126           0 :                       m = vl_api_get_msg_data (am, msg_id);
     127           0 :                       if (m)
     128           0 :                         clib_warning ("msg id %d name %s", (u32) msg_id,
     129             :                                       m->name);
     130             :                     }
     131           0 :                   shmem_hdr->garbage_collects++;
     132           0 :                   goto collected;
     133             :                 }
     134             :             }
     135             : 
     136             : 
     137             :           /* yes, loser; try next larger pool */
     138           0 :           ap[i].misses++;
     139           0 :           if (pool == 0)
     140           0 :             pthread_mutex_unlock (&q->mutex);
     141           0 :           continue;
     142             :         }
     143      735896 :     collected:
     144             : 
     145             :       /* OK, we have a winner */
     146      735896 :       ap[i].hits++;
     147             :       /*
     148             :        * Remember the source queue, although we
     149             :        * don't need to know the queue to free the item.
     150             :        */
     151      735896 :       rv->q = q;
     152      735896 :       rv->gc_mark_timestamp = 0;
     153      735896 :       q->head++;
     154      735896 :       if (q->head == q->maxsize)
     155        2266 :         q->head = 0;
     156             : 
     157      735896 :       if (pool == 0)
     158       63059 :         pthread_mutex_unlock (&q->mutex);
     159      735896 :       goto out;
     160             :     }
     161             : 
     162             :   /*
     163             :    * Request too big, or head element of all size-compatible rings
     164             :    * still in use. Fall back to shared-memory malloc.
     165             :    */
     166       27698 :   am->ring_misses++;
     167             : 
     168       27698 :   oldheap = vl_msg_push_heap_w_region (vlib_rp);
     169       27698 :   if (may_return_null)
     170             :     {
     171           0 :       rv = clib_mem_alloc_or_null (nbytes);
     172           0 :       if (PREDICT_FALSE (rv == 0))
     173             :         {
     174           0 :           vl_msg_pop_heap_w_region (vlib_rp, oldheap);
     175           0 :           return 0;
     176             :         }
     177             :     }
     178             :   else
     179       27698 :     rv = clib_mem_alloc (nbytes);
     180             : 
     181       27698 :   rv->q = 0;
     182       27698 :   rv->gc_mark_timestamp = 0;
     183       27698 :   vl_msg_pop_heap_w_region (vlib_rp, oldheap);
     184             : 
     185      763594 : out:
     186             : #if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
     187             :   {
     188             :     nbytes -= 4;
     189             :     u32 *overrun;
     190             :     overrun = (u32 *) (rv->data + nbytes - sizeof (msgbuf_t));
     191             :     *overrun = 0x1badbabe;
     192             :   }
     193             : #endif
     194      763594 :   rv->data_len = htonl (nbytes - sizeof (msgbuf_t));
     195             : 
     196      763594 :   VL_MSG_API_UNPOISON (rv->data);
     197      763594 :   return (rv->data);
     198             : }
     199             : 
     200             : void *
     201      700738 : vl_msg_api_alloc (int nbytes)
     202             : {
     203             :   int pool;
     204      700738 :   api_main_t *am = vlibapi_get_main ();
     205      700738 :   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
     206             : 
     207             :   /*
     208             :    * Clients use pool-0, vlib proc uses pool 1
     209             :    */
     210      700738 :   pool = (am->our_pid == shmem_hdr->vl_pid);
     211      700738 :   return vl_msg_api_alloc_internal (am->vlib_rp, nbytes, pool,
     212             :                                     0 /* may_return_null */ );
     213             : }
     214             : 
     215             : void *
     216        2839 : vl_msg_api_alloc_zero (int nbytes)
     217             : {
     218             :   void *ret;
     219             : 
     220        2839 :   ret = vl_msg_api_alloc (nbytes);
     221        2839 :   clib_memset (ret, 0, nbytes);
     222        2839 :   return ret;
     223             : }
     224             : 
     225             : void *
     226           1 : vl_msg_api_alloc_or_null (int nbytes)
     227             : {
     228             :   int pool;
     229           1 :   api_main_t *am = vlibapi_get_main ();
     230           1 :   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
     231             : 
     232           1 :   pool = (am->our_pid == shmem_hdr->vl_pid);
     233           1 :   return vl_msg_api_alloc_internal (am->vlib_rp, nbytes, pool,
     234             :                                     1 /* may_return_null */ );
     235             : }
     236             : 
     237             : void *
     238       62385 : vl_msg_api_alloc_as_if_client (int nbytes)
     239             : {
     240       62385 :   api_main_t *am = vlibapi_get_main ();
     241       62385 :   return vl_msg_api_alloc_internal (am->vlib_rp, nbytes, 0,
     242             :                                     0 /* may_return_null */ );
     243             : }
     244             : 
     245             : void *
     246           0 : vl_msg_api_alloc_zero_as_if_client (int nbytes)
     247             : {
     248             :   void *ret;
     249             : 
     250           0 :   ret = vl_msg_api_alloc_as_if_client (nbytes);
     251           0 :   clib_memset (ret, 0, nbytes);
     252           0 :   return ret;
     253             : }
     254             : 
     255             : void *
     256         468 : vl_msg_api_alloc_as_if_client_or_null (int nbytes)
     257             : {
     258         468 :   api_main_t *am = vlibapi_get_main ();
     259         468 :   return vl_msg_api_alloc_internal (am->vlib_rp, nbytes, 0,
     260             :                                     1 /* may_return_null */ );
     261             : }
     262             : 
     263             : void *
     264           2 : vl_mem_api_alloc_as_if_client_w_reg (vl_api_registration_t * reg, int nbytes)
     265             : {
     266           2 :   return vl_msg_api_alloc_internal (reg->vlib_rp, nbytes, 0,
     267             :                                     0 /* may_return_null */ );
     268             : }
     269             : 
     270             : void
     271      763494 : vl_msg_api_free_w_region (svm_region_t * vlib_rp, void *a)
     272             : {
     273             :   msgbuf_t *rv;
     274             :   void *oldheap;
     275             : 
     276      763494 :   rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
     277             : 
     278             :   /*
     279             :    * Here's the beauty of the scheme.  Only one proc/thread has
     280             :    * control of a given message buffer. To free a buffer, we just clear the
     281             :    * queue field, and leave. No locks, no hits, no errors...
     282             :    */
     283      763494 :   if (rv->q)
     284             :     {
     285      735798 :       rv->q = 0;
     286      735798 :       rv->gc_mark_timestamp = 0;
     287             : #if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
     288             :       {
     289             :         u32 *overrun;
     290             :         overrun = (u32 *) (rv->data + ntohl (rv->data_len));
     291             :         ASSERT (*overrun == 0x1badbabe);
     292             :       }
     293             : #endif
     294      735798 :       VL_MSG_API_POISON (rv->data);
     295      735798 :       return;
     296             :     }
     297             : 
     298       27696 :   oldheap = vl_msg_push_heap_w_region (vlib_rp);
     299             : 
     300             : #if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
     301             :   {
     302             :     u32 *overrun;
     303             :     overrun = (u32 *) (rv->data + ntohl (rv->data_len));
     304             :     ASSERT (*overrun == 0x1badbabe);
     305             :   }
     306             : #endif
     307             : 
     308       27696 :   clib_mem_free (rv);
     309       27696 :   vl_msg_pop_heap_w_region (vlib_rp, oldheap);
     310             : }
     311             : 
     312             : void
     313      763494 : vl_msg_api_free (void *a)
     314             : {
     315      763494 :   api_main_t *am = vlibapi_get_main ();
     316      763494 :   vl_msg_api_free_w_region (am->vlib_rp, a);
     317      763494 : }
     318             : 
     319             : static void
     320           0 : vl_msg_api_free_nolock (void *a)
     321             : {
     322             :   msgbuf_t *rv;
     323             :   void *oldheap;
     324           0 :   api_main_t *am = vlibapi_get_main ();
     325             : 
     326           0 :   rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
     327             :   /*
     328             :    * Here's the beauty of the scheme.  Only one proc/thread has
     329             :    * control of a given message buffer. To free a buffer, we just clear the
     330             :    * queue field, and leave. No locks, no hits, no errors...
     331             :    */
     332           0 :   if (rv->q)
     333             :     {
     334           0 :       rv->q = 0;
     335           0 :       VL_MSG_API_POISON (rv->data);
     336           0 :       return;
     337             :     }
     338             : 
     339           0 :   oldheap = svm_push_data_heap (am->vlib_rp);
     340           0 :   clib_mem_free (rv);
     341           0 :   svm_pop_heap (oldheap);
     342             : }
     343             : 
     344             : void
     345         592 : vl_set_memory_root_path (const char *name)
     346             : {
     347         592 :   api_main_t *am = vlibapi_get_main ();
     348             : 
     349         592 :   am->root_path = name;
     350         592 : }
     351             : 
     352             : void
     353           0 : vl_set_memory_uid (int uid)
     354             : {
     355           0 :   api_main_t *am = vlibapi_get_main ();
     356             : 
     357           0 :   am->api_uid = uid;
     358           0 : }
     359             : 
     360             : void
     361           0 : vl_set_memory_gid (int gid)
     362             : {
     363           0 :   api_main_t *am = vlibapi_get_main ();
     364             : 
     365           0 :   am->api_gid = gid;
     366           0 : }
     367             : 
     368             : void
     369           0 : vl_set_global_memory_baseva (u64 baseva)
     370             : {
     371           0 :   api_main_t *am = vlibapi_get_main ();
     372             : 
     373           0 :   am->global_baseva = baseva;
     374           0 : }
     375             : 
     376             : void
     377           0 : vl_set_global_memory_size (u64 size)
     378             : {
     379           0 :   api_main_t *am = vlibapi_get_main ();
     380             : 
     381           0 :   am->global_size = size;
     382           0 : }
     383             : 
     384             : void
     385           0 : vl_set_api_memory_size (u64 size)
     386             : {
     387           0 :   api_main_t *am = vlibapi_get_main ();
     388             : 
     389           0 :   am->api_size = size;
     390           0 : }
     391             : 
     392             : void
     393           0 : vl_set_global_pvt_heap_size (u64 size)
     394             : {
     395           0 :   api_main_t *am = vlibapi_get_main ();
     396             : 
     397           0 :   am->global_pvt_heap_size = size;
     398           0 : }
     399             : 
     400             : void
     401           0 : vl_set_api_pvt_heap_size (u64 size)
     402             : {
     403           0 :   api_main_t *am = vlibapi_get_main ();
     404             : 
     405           0 :   am->api_pvt_heap_size = size;
     406           0 : }
     407             : 
     408             : static void
     409         575 : vl_api_default_mem_config (vl_shmem_hdr_t * shmem_hdr)
     410             : {
     411         575 :   api_main_t *am = vlibapi_get_main ();
     412             :   u32 vlib_input_queue_length;
     413             : 
     414             :   /* vlib main input queue */
     415         575 :   vlib_input_queue_length = 1024;
     416         575 :   if (am->vlib_input_queue_length)
     417           0 :     vlib_input_queue_length = am->vlib_input_queue_length;
     418             : 
     419         575 :   shmem_hdr->vl_input_queue =
     420         575 :     svm_queue_alloc_and_init (vlib_input_queue_length, sizeof (uword),
     421             :                               getpid ());
     422             : 
     423             : #define _(sz,n)                                                 \
     424             :     do {                                                        \
     425             :         ring_alloc_t _rp;                                       \
     426             :         _rp.rp = svm_queue_alloc_and_init ((n), (sz), 0);       \
     427             :         _rp.size = (sz);                                        \
     428             :         _rp.nitems = n;                                         \
     429             :         _rp.hits = 0;                                           \
     430             :         _rp.misses = 0;                                         \
     431             :         vec_add1(shmem_hdr->vl_rings, _rp);                     \
     432             :     } while (0);
     433             : 
     434         575 :   foreach_vl_aring_size;
     435             : #undef _
     436             : 
     437             : #define _(sz,n)                                                 \
     438             :     do {                                                        \
     439             :         ring_alloc_t _rp;                                       \
     440             :         _rp.rp = svm_queue_alloc_and_init ((n), (sz), 0);       \
     441             :         _rp.size = (sz);                                        \
     442             :         _rp.nitems = n;                                         \
     443             :         _rp.hits = 0;                                           \
     444             :         _rp.misses = 0;                                         \
     445             :         vec_add1(shmem_hdr->client_rings, _rp);                 \
     446             :     } while (0);
     447             : 
     448         575 :   foreach_clnt_aring_size;
     449             : #undef _
     450         575 : }
     451             : 
     452             : void
     453         618 : vl_api_mem_config (vl_shmem_hdr_t * hdr, vl_api_shm_elem_config_t * config)
     454             : {
     455             :   vl_api_shm_elem_config_t *c;
     456             :   ring_alloc_t *rp;
     457             :   u32 size;
     458             : 
     459         618 :   if (!config)
     460             :     {
     461         575 :       vl_api_default_mem_config (hdr);
     462         575 :       return;
     463             :     }
     464             : 
     465         344 :   vec_foreach (c, config)
     466             :   {
     467         301 :     switch (c->type)
     468             :       {
     469          43 :       case VL_API_QUEUE:
     470          43 :         hdr->vl_input_queue = svm_queue_alloc_and_init (c->count, c->size,
     471             :                                                         getpid ());
     472          43 :         continue;
     473         129 :       case VL_API_VLIB_RING:
     474         129 :         vec_add2 (hdr->vl_rings, rp, 1);
     475         129 :         break;
     476         129 :       case VL_API_CLIENT_RING:
     477         129 :         vec_add2 (hdr->client_rings, rp, 1);
     478         129 :         break;
     479           0 :       default:
     480           0 :         clib_warning ("unknown config type: %d", c->type);
     481           0 :         continue;
     482             :       }
     483             : 
     484         258 :     size = sizeof (ring_alloc_t) + c->size;
     485         258 :     rp->rp = svm_queue_alloc_and_init (c->count, size, 0);
     486         258 :     rp->size = size;
     487         258 :     rp->nitems = c->count;
     488         258 :     rp->hits = 0;
     489         258 :     rp->misses = 0;
     490             :   }
     491             : }
     492             : 
     493             : void
     494         618 : vl_init_shmem (svm_region_t * vlib_rp, vl_api_shm_elem_config_t * config,
     495             :                int is_vlib, int is_private_region)
     496             : {
     497         618 :   api_main_t *am = vlibapi_get_main ();
     498         618 :   vl_shmem_hdr_t *shmem_hdr = 0;
     499             :   void *oldheap;
     500         618 :   ASSERT (vlib_rp);
     501             : 
     502             :   /* $$$$ need private region config parameters */
     503             : 
     504         618 :   oldheap = svm_push_data_heap (vlib_rp);
     505             : 
     506         618 :   vec_validate (shmem_hdr, 0);
     507         618 :   shmem_hdr->version = VL_SHM_VERSION;
     508         618 :   shmem_hdr->clib_file_index = VL_API_INVALID_FI;
     509             : 
     510             :   /* Set up the queue and msg ring allocator */
     511         618 :   vl_api_mem_config (shmem_hdr, config);
     512             : 
     513         618 :   if (is_private_region == 0)
     514             :     {
     515         575 :       am->shmem_hdr = shmem_hdr;
     516         575 :       am->vlib_rp = vlib_rp;
     517         575 :       am->our_pid = getpid ();
     518         575 :       if (is_vlib)
     519         575 :         am->shmem_hdr->vl_pid = am->our_pid;
     520             :     }
     521             :   else
     522          43 :     shmem_hdr->vl_pid = am->our_pid;
     523             : 
     524         618 :   svm_pop_heap (oldheap);
     525             : 
     526             :   /*
     527             :    * After absolutely everything that a client might see is set up,
     528             :    * declare the shmem region valid
     529             :    */
     530         618 :   vlib_rp->user_ctx = shmem_hdr;
     531             : 
     532         618 :   pthread_mutex_unlock (&vlib_rp->mutex);
     533         618 : }
     534             : 
     535             : int
     536         592 : vl_map_shmem (const char *region_name, int is_vlib)
     537             : {
     538         592 :   svm_map_region_args_t _a, *a = &_a;
     539             :   svm_region_t *vlib_rp, *root_rp;
     540         592 :   api_main_t *am = vlibapi_get_main ();
     541             :   int i;
     542             :   struct timespec ts, tsrem;
     543         592 :   char *vpe_api_region_suffix = "-vpe-api";
     544             : 
     545         592 :   clib_memset (a, 0, sizeof (*a));
     546             : 
     547         592 :   if (strstr (region_name, vpe_api_region_suffix))
     548             :     {
     549           0 :       u8 *root_path = format (0, "%s", region_name);
     550           0 :       vec_set_len (root_path,
     551             :                    vec_len (root_path) - strlen (vpe_api_region_suffix));
     552           0 :       vec_terminate_c_string (root_path);
     553           0 :       a->root_path = (const char *) root_path;
     554           0 :       am->root_path = (const char *) root_path;
     555             :     }
     556             : 
     557         592 :   if (is_vlib == 0)
     558             :     {
     559             :       int tfd;
     560             :       u8 *api_name;
     561             :       /*
     562             :        * Clients wait for vpp to set up the root / API regioins
     563             :        */
     564          17 :       if (am->root_path)
     565          17 :         api_name = format (0, "/dev/shm/%s-%s%c", am->root_path,
     566             :                            region_name + 1, 0);
     567             :       else
     568           0 :         api_name = format (0, "/dev/shm%s%c", region_name, 0);
     569             : 
     570             :       /* Wait up to 100 seconds... */
     571          17 :       for (i = 0; i < 10000; i++)
     572             :         {
     573          17 :           ts.tv_sec = 0;
     574          17 :           ts.tv_nsec = 10000 * 1000;    /* 10 ms */
     575          17 :           while (nanosleep (&ts, &tsrem) < 0)
     576           0 :             ts = tsrem;
     577          17 :           tfd = open ((char *) api_name, O_RDWR);
     578          17 :           if (tfd >= 0)
     579          17 :             break;
     580             :         }
     581          17 :       vec_free (api_name);
     582          17 :       if (tfd < 0)
     583             :         {
     584           0 :           clib_warning ("region init fail");
     585           0 :           return -2;
     586             :         }
     587          17 :       close (tfd);
     588          17 :       svm_region_init_chroot_uid_gid (am->root_path, getuid (), getgid ());
     589             :     }
     590             : 
     591         592 :   if (a->root_path != NULL)
     592             :     {
     593           0 :       a->name = "/vpe-api";
     594             :     }
     595             :   else
     596         592 :     a->name = region_name;
     597         592 :   a->size = am->api_size ? am->api_size : (16 << 20);
     598         592 :   a->flags = SVM_FLAGS_MHEAP;
     599         592 :   a->uid = am->api_uid;
     600         592 :   a->gid = am->api_gid;
     601         592 :   a->pvt_heap_size = am->api_pvt_heap_size;
     602             : 
     603         592 :   vlib_rp = svm_region_find_or_create (a);
     604             : 
     605         592 :   if (vlib_rp == 0)
     606           0 :     return (-2);
     607             : 
     608         592 :   pthread_mutex_lock (&vlib_rp->mutex);
     609             :   /* Has someone else set up the shared-memory variable table? */
     610         592 :   if (vlib_rp->user_ctx)
     611             :     {
     612          17 :       am->shmem_hdr = (void *) vlib_rp->user_ctx;
     613          17 :       am->our_pid = getpid ();
     614          17 :       if (is_vlib)
     615             :         {
     616             :           svm_queue_t *q;
     617             :           uword old_msg;
     618             :           /*
     619             :            * application restart. Reset cached pids, API message
     620             :            * rings, list of clients; otherwise, various things
     621             :            * fail. (e.g. queue non-empty notification)
     622             :            */
     623             : 
     624             :           /* ghosts keep the region from disappearing properly */
     625           0 :           svm_client_scan_this_region_nolock (vlib_rp);
     626           0 :           am->shmem_hdr->application_restarts++;
     627           0 :           q = am->shmem_hdr->vl_input_queue;
     628           0 :           am->shmem_hdr->vl_pid = getpid ();
     629           0 :           q->consumer_pid = am->shmem_hdr->vl_pid;
     630             :           /* Drain the input queue, freeing msgs */
     631           0 :           for (i = 0; i < 10; i++)
     632             :             {
     633           0 :               if (pthread_mutex_trylock (&q->mutex) == 0)
     634             :                 {
     635           0 :                   pthread_mutex_unlock (&q->mutex);
     636           0 :                   goto mutex_ok;
     637             :                 }
     638           0 :               ts.tv_sec = 0;
     639           0 :               ts.tv_nsec = 10000 * 1000;        /* 10 ms */
     640           0 :               while (nanosleep (&ts, &tsrem) < 0)
     641           0 :                 ts = tsrem;
     642             :             }
     643             :           /* Mutex buggered, "fix" it */
     644           0 :           clib_memset (&q->mutex, 0, sizeof (q->mutex));
     645           0 :           clib_warning ("forcibly release main input queue mutex");
     646             : 
     647           0 :         mutex_ok:
     648           0 :           am->vlib_rp = vlib_rp;
     649           0 :           while (svm_queue_sub (q, (u8 *) & old_msg, SVM_Q_NOWAIT, 0)
     650             :                  != -2 /* queue underflow */ )
     651             :             {
     652           0 :               vl_msg_api_free_nolock ((void *) old_msg);
     653           0 :               am->shmem_hdr->restart_reclaims++;
     654             :             }
     655           0 :           pthread_mutex_unlock (&vlib_rp->mutex);
     656           0 :           root_rp = svm_get_root_rp ();
     657           0 :           ASSERT (root_rp);
     658             :           /* Clean up the root region client list */
     659           0 :           pthread_mutex_lock (&root_rp->mutex);
     660           0 :           svm_client_scan_this_region_nolock (root_rp);
     661           0 :           pthread_mutex_unlock (&root_rp->mutex);
     662             :         }
     663             :       else
     664             :         {
     665          17 :           pthread_mutex_unlock (&vlib_rp->mutex);
     666             :         }
     667          17 :       am->vlib_rp = vlib_rp;
     668          17 :       vec_add1 (am->mapped_shmem_regions, vlib_rp);
     669          17 :       return 0;
     670             :     }
     671             :   /* Clients simply have to wait... */
     672         575 :   if (!is_vlib)
     673             :     {
     674           0 :       pthread_mutex_unlock (&vlib_rp->mutex);
     675             : 
     676             :       /* Wait up to 100 seconds... */
     677           0 :       for (i = 0; i < 10000; i++)
     678             :         {
     679           0 :           ts.tv_sec = 0;
     680           0 :           ts.tv_nsec = 10000 * 1000;    /* 10 ms */
     681           0 :           while (nanosleep (&ts, &tsrem) < 0)
     682           0 :             ts = tsrem;
     683           0 :           if (vlib_rp->user_ctx)
     684           0 :             goto ready;
     685             :         }
     686             :       /* Clean up and leave... */
     687           0 :       svm_region_unmap (vlib_rp);
     688           0 :       clib_warning ("region init fail");
     689           0 :       return (-2);
     690             : 
     691           0 :     ready:
     692           0 :       am->shmem_hdr = (void *) vlib_rp->user_ctx;
     693           0 :       am->our_pid = getpid ();
     694           0 :       am->vlib_rp = vlib_rp;
     695           0 :       vec_add1 (am->mapped_shmem_regions, vlib_rp);
     696           0 :       return 0;
     697             :     }
     698             : 
     699             :   /* Nope, it's our problem... */
     700         575 :   vl_init_shmem (vlib_rp, 0 /* default config */ , 1 /* is vlib */ ,
     701             :                  0 /* is_private_region */ );
     702             : 
     703         575 :   vec_add1 (am->mapped_shmem_regions, vlib_rp);
     704         575 :   return 0;
     705             : }
     706             : 
     707             : void
     708           0 : vl_register_mapped_shmem_region (svm_region_t * rp)
     709             : {
     710           0 :   api_main_t *am = vlibapi_get_main ();
     711             : 
     712           0 :   vec_add1 (am->mapped_shmem_regions, rp);
     713           0 : }
     714             : 
     715             : static void
     716         622 : vl_unmap_shmem_internal (u8 is_client)
     717             : {
     718             :   svm_region_t *rp;
     719             :   int i;
     720         622 :   api_main_t *am = vlibapi_get_main ();
     721             : 
     722         622 :   if (!svm_get_root_rp ())
     723          29 :     return;
     724             : 
     725        1186 :   for (i = 0; i < vec_len (am->mapped_shmem_regions); i++)
     726             :     {
     727         593 :       rp = am->mapped_shmem_regions[i];
     728         593 :       is_client ? svm_region_unmap_client (rp) : svm_region_unmap (rp);
     729             :     }
     730             : 
     731         593 :   vec_free (am->mapped_shmem_regions);
     732         593 :   am->shmem_hdr = 0;
     733             : 
     734         593 :   is_client ? svm_region_exit_client () : svm_region_exit ();
     735             : 
     736         593 :   vec_free (am->msg_data);
     737             : }
     738             : 
     739             : void
     740         576 : vl_unmap_shmem (void)
     741             : {
     742         576 :   vl_unmap_shmem_internal (0);
     743         576 : }
     744             : 
     745             : void
     746          46 : vl_unmap_shmem_client (void)
     747             : {
     748          46 :   vl_unmap_shmem_internal (1);
     749          46 : }
     750             : 
     751             : void
     752       63771 : vl_msg_api_send_shmem (svm_queue_t * q, u8 * elem)
     753             : {
     754       63771 :   api_main_t *am = vlibapi_get_main ();
     755       63771 :   void *msg = (void *) *(uword *) elem;
     756             : 
     757       63771 :   if (am->tx_trace && am->tx_trace->enabled)
     758           0 :     vl_msg_api_trace (am, am->tx_trace, msg);
     759             : 
     760             :   /*
     761             :    * Announce a probable binary API client bug:
     762             :    * some client's input queue is stuffed.
     763             :    * The situation may be recoverable, or not.
     764             :    */
     765       63771 :   if (PREDICT_FALSE
     766             :       (am->vl_clients /* vpp side */  && (q->cursize == q->maxsize)))
     767             :     {
     768           0 :       if (PREDICT_FALSE (am->elog_trace_api_messages))
     769             :         {
     770             :           /* *INDENT-OFF* */
     771             :           ELOG_TYPE_DECLARE (e) =
     772             :             {
     773             :               .format = "api-client-queue-stuffed: %x%x",
     774             :               .format_args = "i4i4",
     775             :             };
     776             :           /* *INDENT-ON* */
     777             :           struct
     778             :           {
     779             :             u32 hi, low;
     780             :           } *ed;
     781           0 :           ed = ELOG_DATA (am->elog_main, e);
     782           0 :           ed->hi = (uword) q >> 32;
     783           0 :           ed->low = (uword) q & 0xFFFFFFFF;
     784           0 :           clib_warning ("WARNING: client input queue at %llx is stuffed...",
     785             :                         q);
     786             :         }
     787             :     }
     788       63771 :   VL_MSG_API_POISON (msg);
     789       63771 :   (void) svm_queue_add (q, elem, 0 /* nowait */ );
     790       63771 : }
     791             : 
     792             : int
     793           0 : vl_mem_api_can_send (svm_queue_t * q)
     794             : {
     795           0 :   return (q->cursize < q->maxsize);
     796             : }
     797             : 
     798             : void
     799           0 : vl_msg_api_send_shmem_nolock (svm_queue_t * q, u8 * elem)
     800             : {
     801           0 :   api_main_t *am = vlibapi_get_main ();
     802           0 :   void *msg = (void *) *(uword *) elem;
     803             : 
     804           0 :   if (am->tx_trace && am->tx_trace->enabled)
     805           0 :     vl_msg_api_trace (am, am->tx_trace, msg);
     806             : 
     807           0 :   (void) svm_queue_add_nolock (q, elem);
     808           0 :   VL_MSG_API_POISON (msg);
     809           0 : }
     810             : 
     811             : /*
     812             :  * fd.io coding-style-patch-verification: ON
     813             :  *
     814             :  * Local Variables:
     815             :  * eval: (c-set-style "gnu")
     816             :  * End:
     817             :  */

Generated by: LCOV version 1.14