svm: decouple fifo and default chunk allocation
[vpp.git] / src / svm / fifo_segment.c
1 /*
2  * Copyright (c) 2016-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <svm/fifo_segment.h>
17
18 /**
19  * Initialize fifo segment shared header
20  */
21 int
22 fifo_segment_init (fifo_segment_t * fs)
23 {
24   fifo_segment_header_t *fsh;
25   ssvm_shared_header_t *sh;
26   void *oldheap;
27
28   sh = fs->ssvm.sh;
29   oldheap = ssvm_push_heap (sh);
30
31   fsh = clib_mem_alloc (sizeof (*fsh));
32   clib_memset (fsh, 0, sizeof (*fsh));
33   fs->h = sh->opaque[0] = fsh;
34
35   ssvm_pop_heap (oldheap);
36
37   sh->ready = 1;
38   return (0);
39 }
40
41 /**
42  * Create a fifo segment in process-private memory
43  */
44 static int
45 fifo_segment_create_process_private (fifo_segment_main_t * sm,
46                                      fifo_segment_create_args_t * a)
47 {
48   u32 pagesize = clib_mem_get_page_size ();
49   ssvm_shared_header_t *sh;
50   fifo_segment_t *s;
51   u32 rnd_size = 0;
52   u8 *heap;
53
54   pool_get (sm->segments, s);
55   clib_memset (s, 0, sizeof (*s));
56
57   rnd_size = (a->segment_size + (pagesize - 1)) & ~pagesize;
58
59 #if USE_DLMALLOC == 0
60   heap = mheap_alloc (0, rnd_size);
61   if (heap == 0)
62     {
63       clib_unix_warning ("mheap alloc");
64       pool_put (sm->segments, s);
65       return -1;
66     }
67   {
68     mheap_t *heap_header;
69     heap_header = mheap_header (heap);
70     heap_header->flags |= MHEAP_FLAG_THREAD_SAFE;
71   }
72 #else
73   heap = create_mspace (rnd_size, 1 /* locked */ );
74 #endif
75
76   s->ssvm.ssvm_size = rnd_size;
77   s->ssvm.i_am_master = 1;
78   s->ssvm.my_pid = getpid ();
79   s->ssvm.name = format (0, "%s%c", a->segment_name, 0);
80   s->ssvm.requested_va = ~0;
81
82   /* Allocate a [sic] shared memory header, in process memory... */
83   sh = clib_mem_alloc_aligned (sizeof (*sh), CLIB_CACHE_LINE_BYTES);
84   s->ssvm.sh = sh;
85
86   clib_memset (sh, 0, sizeof (*sh));
87   sh->heap = heap;
88
89   fifo_segment_init (s);
90   vec_add1 (a->new_segment_indices, s - sm->segments);
91
92   return (0);
93 }
94
95 /**
96  * Create a fifo segment and initialize as master
97  */
98 int
99 fifo_segment_create (fifo_segment_main_t * sm, fifo_segment_create_args_t * a)
100 {
101   fifo_segment_t *s;
102   int rv;
103
104   if (a->segment_type == SSVM_SEGMENT_PRIVATE)
105     return fifo_segment_create_process_private (sm, a);
106
107   /* Allocate a fresh segment */
108   pool_get (sm->segments, s);
109   clib_memset (s, 0, sizeof (*s));
110
111   s->ssvm.ssvm_size = a->segment_size;
112   s->ssvm.i_am_master = 1;
113   s->ssvm.my_pid = getpid ();
114   s->ssvm.name = format (0, "%s%c", a->segment_name, 0);
115   s->ssvm.requested_va = sm->next_baseva;
116
117   if ((rv = ssvm_master_init (&s->ssvm, a->segment_type)))
118     {
119       pool_put (sm->segments, s);
120       return (rv);
121     }
122
123   /* Note: requested_va updated due to seg base addr randomization */
124   sm->next_baseva = s->ssvm.sh->ssvm_va + a->segment_size;
125
126   fifo_segment_init (s);
127   vec_add1 (a->new_segment_indices, s - sm->segments);
128   return (0);
129 }
130
131 /**
132  * Attach as slave to a fifo segment
133  */
134 int
135 fifo_segment_attach (fifo_segment_main_t * sm, fifo_segment_create_args_t * a)
136 {
137   fifo_segment_t *s;
138   int rv;
139
140   pool_get_zero (sm->segments, s);
141
142   s->ssvm.ssvm_size = a->segment_size;
143   s->ssvm.my_pid = getpid ();
144   s->ssvm.name = format (0, "%s%c", a->segment_name, 0);
145   s->ssvm.requested_va = sm->next_baseva;
146   if (a->segment_type == SSVM_SEGMENT_MEMFD)
147     s->ssvm.fd = a->memfd_fd;
148   else
149     s->ssvm.attach_timeout = sm->timeout_in_seconds;
150
151   if ((rv = ssvm_slave_init (&s->ssvm, a->segment_type)))
152     {
153       _vec_len (s) = vec_len (s) - 1;
154       return (rv);
155     }
156
157   /* Fish the segment header */
158   s->h = s->ssvm.sh->opaque[0];
159
160   vec_add1 (a->new_segment_indices, s - sm->segments);
161   return (0);
162 }
163
164 void
165 fifo_segment_delete (fifo_segment_main_t * sm, fifo_segment_t * s)
166 {
167   ssvm_delete (&s->ssvm);
168   clib_memset (s, 0xfe, sizeof (*s));
169   pool_put (sm->segments, s);
170 }
171
172 u32
173 fifo_segment_index (fifo_segment_main_t * sm, fifo_segment_t * s)
174 {
175   return s - sm->segments;
176 }
177
178 void *
179 svm_fifo_segment_heap (fifo_segment_t * seg)
180 {
181   return seg->ssvm.sh->heap;
182 }
183
184 fifo_segment_t *
185 fifo_segment_get_segment (fifo_segment_main_t * sm, u32 segment_index)
186 {
187   return pool_elt_at_index (sm->segments, segment_index);
188 }
189
190 void
191 fifo_segment_info (fifo_segment_t * seg, char **address, size_t * size)
192 {
193   if (ssvm_type (&seg->ssvm) == SSVM_SEGMENT_PRIVATE)
194     {
195 #if USE_DLMALLOC == 0
196       mheap_t *heap_header;
197
198       *address = pointer_to_uword (seg->ssvm.sh->heap);
199       heap_header = mheap_header (seg->ssvm.sh->heap);
200       *size = heap_header->max_size;
201 #else
202       mspace_get_address_and_size (seg->ssvm.sh->heap, address, size);
203 #endif
204     }
205   else
206     {
207       *address = (char *) seg->ssvm.sh->ssvm_va;
208       *size = seg->ssvm.ssvm_size;
209     }
210 }
211
212 void
213 fifo_segment_main_init (fifo_segment_main_t * sm, u64 baseva,
214                         u32 timeout_in_seconds)
215 {
216   sm->next_baseva = baseva;
217   sm->timeout_in_seconds = timeout_in_seconds;
218 }
219
220 static void
221 fifo_init_for_segment (svm_fifo_t * f, svm_fifo_chunk_t * c)
222 {
223   f->start_chunk = f->end_chunk = c->next = c;
224   f->head_chunk = f->tail_chunk = f->ooo_enq = f->ooo_deq = f->start_chunk;
225 }
226
227 static void
228 fifo_init_chunk_for_segment (svm_fifo_chunk_t * c, u32 size)
229 {
230   c->start_byte = 0;
231   c->length = size;
232   c->next = 0;
233 }
234
235 static inline int
236 fs_free_list_for_size (u32 size)
237 {
238   return max_log2 (size) - max_log2 (FIFO_SEGMENT_MIN_FIFO_SIZE);
239 }
240
241 static inline int
242 fs_chunk_size_is_valid (u32 size)
243 {
244   /*
245    * 4K minimum. It's not likely that anything good will happen
246    * with a smaller FIFO.
247    */
248   return size >= FIFO_SEGMENT_MIN_FIFO_SIZE
249     && size <= FIFO_SEGMENT_MAX_FIFO_SIZE;
250 }
251
252 static svm_fifo_t *
253 fs_try_alloc_fifo_from_freelist (fifo_segment_header_t * fsh, u32 data_bytes)
254 {
255   svm_fifo_chunk_t *c;
256   svm_fifo_t *f;
257   u32 fl_index;
258
259   f = fsh->free_fifos;
260   fl_index = fs_free_list_for_size (data_bytes);
261   vec_validate_init_empty (fsh->free_chunks, fl_index, 0);
262   c = fsh->free_chunks[fl_index];
263
264   if (!f || !c)
265     return 0;
266
267   fsh->free_fifos = f->next;
268   fsh->free_chunks[fl_index] = c->next;
269   c->next = c;
270   c->start_byte = 0;
271   c->length = data_bytes;
272   memset (f, 0, sizeof (*f));
273   f->start_chunk = c;
274   f->end_chunk = c;
275   return f;
276 }
277
278 static svm_fifo_t *
279 fs_try_allocate_fifo_batch (ssvm_shared_header_t * sh,
280                             fifo_segment_header_t * fsh, u32 data_bytes)
281 {
282   u32 size, rounded_data_size;
283   svm_fifo_chunk_t *c;
284   u32 fl_index, hdrs;
285   svm_fifo_t *f;
286   void *oldheap;
287   u8 *fmem;
288   int i;
289
290   rounded_data_size = (1 << (max_log2 (data_bytes)));
291   fl_index = fs_free_list_for_size (data_bytes);
292   vec_validate_init_empty (fsh->free_chunks, fl_index, 0);
293
294   oldheap = ssvm_push_heap (sh);
295   hdrs = sizeof (*f) + sizeof (*c);
296   size = (hdrs + rounded_data_size) * FIFO_SEGMENT_ALLOC_BATCH_SIZE;
297   fmem = clib_mem_alloc_aligned_at_offset (size, CLIB_CACHE_LINE_BYTES,
298                                            0 /* align_offset */ ,
299                                            0 /* os_out_of_memory */ );
300   ssvm_pop_heap (oldheap);
301
302   /* Out of space.. */
303   if (fmem == 0)
304     return 0;
305
306   /* Carve fifo + chunk space */
307   for (i = 0; i < FIFO_SEGMENT_ALLOC_BATCH_SIZE; i++)
308     {
309       f = (svm_fifo_t *) fmem;
310       memset (f, 0, sizeof (*f));
311       f->next = fsh->free_fifos;
312       fsh->free_fifos = f;
313       c = (svm_fifo_chunk_t *) (fmem + sizeof (*f));
314       c->start_byte = 0;
315       c->length = rounded_data_size;
316       c->next = fsh->free_chunks[fl_index];
317       fsh->free_chunks[fl_index] = c;
318       fmem += hdrs + rounded_data_size;
319     }
320
321   return fs_try_alloc_fifo_from_freelist (fsh, data_bytes);
322 }
323
324 /**
325  * Allocate fifo in fifo segment
326  */
327 svm_fifo_t *
328 fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes,
329                          fifo_segment_ftype_t ftype)
330 {
331   fifo_segment_header_t *fsh;
332   ssvm_shared_header_t *sh;
333   svm_fifo_t *f = 0;
334
335   if (!fs_chunk_size_is_valid (data_bytes))
336     {
337       clib_warning ("fifo size out of range %d", data_bytes);
338       return 0;
339     }
340
341   sh = fs->ssvm.sh;
342   ssvm_lock_non_recursive (sh, 1);
343   fsh = fs->h;
344
345   /* Try the following steps in order:
346    * - grab fifo and chunk from freelists
347    * - batch fifo and chunk allocation
348    * - single fifo allocation
349    */
350   f = fs_try_alloc_fifo_from_freelist (fsh, data_bytes);
351   if (!f)
352     f = fs_try_allocate_fifo_batch (sh, fsh, data_bytes);
353   if (!f)
354     {
355       void *oldheap = ssvm_push_heap (sh);
356       f = svm_fifo_create (data_bytes);
357       ssvm_pop_heap (oldheap);
358       if (!f)
359         goto done;
360     }
361
362   /* (re)initialize the fifo, as in svm_fifo_create */
363   svm_fifo_init (f, data_bytes);
364
365   /* If rx fifo type add to active fifos list. When cleaning up segment,
366    * we need a list of active sessions that should be disconnected. Since
367    * both rx and tx fifos keep pointers to the session, it's enough to track
368    * only one. */
369   if (ftype == FIFO_SEGMENT_RX_FIFO)
370     {
371       if (fsh->fifos)
372         {
373           fsh->fifos->prev = f;
374           f->next = fsh->fifos;
375         }
376       fsh->fifos = f;
377       f->flags |= SVM_FIFO_F_LL_TRACKED;
378     }
379   fsh->n_active_fifos++;
380
381 done:
382   ssvm_unlock_non_recursive (sh);
383   return (f);
384 }
385
386 /**
387  * Free fifo allocated in fifo segment
388  */
389 void
390 fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f)
391 {
392   svm_fifo_chunk_t *cur, *next;
393   fifo_segment_header_t *fsh;
394   ssvm_shared_header_t *sh;
395   void *oldheap;
396   int fl_index;
397
398   ASSERT (f->refcnt > 0);
399
400   if (--f->refcnt > 0)
401     return;
402
403   sh = fs->ssvm.sh;
404   fsh = fs->h;
405
406   ssvm_lock_non_recursive (sh, 2);
407
408   /* Remove from active list. Only rx fifos are tracked */
409   if (f->flags & SVM_FIFO_F_LL_TRACKED)
410     {
411       if (f->prev)
412         f->prev->next = f->next;
413       else
414         fsh->fifos = f->next;
415       if (f->next)
416         f->next->prev = f->prev;
417       f->flags &= ~SVM_FIFO_F_LL_TRACKED;
418     }
419
420   /* Add to free list */
421   f->next = fsh->free_fifos;
422   f->prev = 0;
423   fsh->free_fifos = f;
424
425   /* Free fifo chunks */
426   cur = f->start_chunk;
427   do
428     {
429       next = cur->next;
430       fl_index = fs_free_list_for_size (cur->length);
431       ASSERT (fl_index < vec_len (fsh->free_chunks));
432       cur->next = fsh->free_chunks[fl_index];
433       fsh->free_chunks[fl_index] = cur;
434       cur = next;
435     }
436   while (cur != f->start_chunk);
437
438   oldheap = ssvm_push_heap (sh);
439   svm_fifo_free_chunk_lookup (f);
440   ssvm_pop_heap (oldheap);
441
442   /* not allocated on segment heap */
443   svm_fifo_free_ooo_data (f);
444
445   if (CLIB_DEBUG)
446     {
447       f->master_session_index = ~0;
448       f->master_thread_index = ~0;
449     }
450
451   fsh->n_active_fifos--;
452   ssvm_unlock_non_recursive (sh);
453 }
454
455 /**
456  * Pre-allocates fifo pairs in fifo segment
457  */
458 void
459 fifo_segment_preallocate_fifo_pairs (fifo_segment_t * fs,
460                                      u32 rx_fifo_size, u32 tx_fifo_size,
461                                      u32 * n_fifo_pairs)
462 {
463   u32 rx_rounded_data_size, tx_rounded_data_size, pair_size;
464   u32 rx_fifos_size, tx_fifos_size, pairs_to_allocate;
465   ssvm_shared_header_t *sh = fs->ssvm.sh;
466   fifo_segment_header_t *fsh = fs->h;
467   int i, rx_fl_index, tx_fl_index;
468   u8 *rx_fifo_mem, *tx_fifo_mem;
469   uword space_available;
470   svm_fifo_chunk_t *c;
471   void *oldheap;
472   svm_fifo_t *f;
473   u32 hdrs;
474
475   /* Parameter check */
476   if (rx_fifo_size == 0 || tx_fifo_size == 0 || *n_fifo_pairs == 0)
477     return;
478
479   if (!fs_chunk_size_is_valid (rx_fifo_size))
480     {
481       clib_warning ("rx fifo_size out of range %d", rx_fifo_size);
482       return;
483     }
484
485   if (!fs_chunk_size_is_valid (tx_fifo_size))
486     {
487       clib_warning ("tx fifo_size out of range %d", tx_fifo_size);
488       return;
489     }
490
491   rx_rounded_data_size = (1 << (max_log2 (rx_fifo_size)));
492   rx_fl_index = fs_free_list_for_size (rx_fifo_size);
493   tx_rounded_data_size = (1 << (max_log2 (tx_fifo_size)));
494   tx_fl_index = fs_free_list_for_size (tx_fifo_size);
495
496   hdrs = sizeof (*f) + sizeof (*c);
497
498   /* Calculate space requirements */
499   pair_size = 2 * hdrs + rx_rounded_data_size + tx_rounded_data_size;
500 #if USE_DLMALLOC == 0
501   space_available = fs->ssvm.ssvm_size - mheap_bytes (sh->heap);
502 #else
503   space_available = fs->ssvm.ssvm_size - mspace_usable_size (sh->heap);
504 #endif
505
506   pairs_to_allocate = clib_min (space_available / pair_size, *n_fifo_pairs);
507   rx_fifos_size = (hdrs + rx_rounded_data_size) * pairs_to_allocate;
508   tx_fifos_size = (hdrs + tx_rounded_data_size) * pairs_to_allocate;
509
510   vec_validate_init_empty (fsh->free_chunks,
511                            clib_max (rx_fl_index, tx_fl_index), 0);
512
513   oldheap = ssvm_push_heap (sh);
514
515   /* Allocate rx and tx fifo memory. May fail. */
516   rx_fifo_mem = clib_mem_alloc_aligned_at_offset (rx_fifos_size,
517                                                   CLIB_CACHE_LINE_BYTES,
518                                                   0 /* align_offset */ ,
519                                                   0 /* os_out_of_memory */ );
520   tx_fifo_mem = clib_mem_alloc_aligned_at_offset (tx_fifos_size,
521                                                   CLIB_CACHE_LINE_BYTES,
522                                                   0 /* align_offset */ ,
523                                                   0 /* os_out_of_memory */ );
524
525   /* Make sure it worked. Clean up if it didn't... */
526   if (rx_fifo_mem == 0 || tx_fifo_mem == 0)
527     {
528       rx_fifo_mem ? clib_mem_free (rx_fifo_mem) : clib_mem_free (tx_fifo_mem);
529       clib_warning ("fifo preallocation failure: rx size %d tx size %u "
530                     "npairs %d", rx_fifo_size, tx_fifo_size, *n_fifo_pairs);
531       ssvm_pop_heap (oldheap);
532       return;
533     }
534
535   /* Carve rx and tx fifo memory */
536   for (i = 0; i < pairs_to_allocate; i++)
537     {
538       f = (svm_fifo_t *) rx_fifo_mem;
539       c = (svm_fifo_chunk_t *) (rx_fifo_mem + sizeof (*f));
540       fifo_init_chunk_for_segment (c, rx_rounded_data_size);
541       fifo_init_for_segment (f, c);
542       rx_fifo_mem += hdrs + rx_rounded_data_size;
543
544       f = (svm_fifo_t *) tx_fifo_mem;
545       c = (svm_fifo_chunk_t *) (tx_fifo_mem + sizeof (*f));
546       fifo_init_chunk_for_segment (c, tx_rounded_data_size);
547       fifo_init_for_segment (f, c);
548       tx_fifo_mem += hdrs + tx_rounded_data_size;
549     }
550
551   /* Account for the pairs allocated */
552   *n_fifo_pairs -= pairs_to_allocate;
553   ssvm_pop_heap (oldheap);
554 }
555
556 int
557 fifo_segment_grow_fifo (fifo_segment_t * fs, svm_fifo_t * f, u32 chunk_size)
558 {
559   ssvm_shared_header_t *sh;
560   svm_fifo_chunk_t *c;
561   void *oldheap;
562   int fl_index;
563
564   if (!fs_chunk_size_is_valid (chunk_size))
565     {
566       clib_warning ("chunk size out of range %d", chunk_size);
567       return 0;
568     }
569
570   fl_index = fs_free_list_for_size (chunk_size);
571
572   sh = fs->ssvm.sh;
573   ssvm_lock_non_recursive (sh, 1);
574
575   vec_validate_init_empty (fs->h->free_chunks, fl_index, 0);
576   c = fs->h->free_chunks[fl_index];
577
578   oldheap = ssvm_push_heap (sh);
579
580   if (!c)
581     {
582       c = svm_fifo_chunk_alloc (chunk_size);
583       if (!c)
584         {
585           ssvm_pop_heap (oldheap);
586           return -1;
587         }
588     }
589   else
590     {
591       fs->h->free_chunks[fl_index] = c->next;
592       c->next = 0;
593     }
594
595   svm_fifo_add_chunk (f, c);
596
597   ssvm_pop_heap (oldheap);
598   ssvm_unlock_non_recursive (sh);
599   return 0;
600 }
601
602 int
603 fifo_segment_collect_fifo_chunks (fifo_segment_t * fs, svm_fifo_t * f)
604 {
605   svm_fifo_chunk_t *cur, *next;
606   ssvm_shared_header_t *sh;
607   void *oldheap;
608   int fl_index;
609
610   sh = fs->ssvm.sh;
611   ssvm_lock_non_recursive (sh, 1);
612
613   oldheap = ssvm_push_heap (sh);
614   cur = svm_fifo_collect_chunks (f);
615
616   while (cur)
617     {
618       next = cur->next;
619       fl_index = fs_free_list_for_size (cur->length);
620       cur->next = fs->h->free_chunks[fl_index];
621       fs->h->free_chunks[fl_index] = cur;
622       cur = next;
623     }
624
625   ssvm_pop_heap (oldheap);
626   ssvm_unlock_non_recursive (sh);
627
628   return 0;
629 }
630
631 /**
632  * Get number of active fifos
633  */
634 u32
635 fifo_segment_num_fifos (fifo_segment_t * fs)
636 {
637   return fs->h->n_active_fifos;
638 }
639
640 u32
641 fifo_segment_num_free_fifos (fifo_segment_t * fs, u32 fifo_size_in_bytes)
642 {
643   fifo_segment_header_t *fsh;
644   ssvm_shared_header_t *sh;
645   svm_fifo_t *f;
646   u32 count = 0;
647
648   sh = fs->ssvm.sh;
649   fsh = (fifo_segment_header_t *) sh->opaque[0];
650
651   f = fsh->free_fifos;
652   if (f == 0)
653     return 0;
654
655   while (f)
656     {
657       f = f->next;
658       count++;
659     }
660   return count;
661 }
662
663 u32
664 fifo_segment_num_free_chunks (fifo_segment_t * fs, u32 size)
665 {
666   u32 count = 0, rounded_size, fl_index;
667   fifo_segment_header_t *fsh;
668   svm_fifo_chunk_t *c;
669   int i;
670
671   fsh = fs->h;
672
673   /* Count all free chunks? */
674   if (size == ~0)
675     {
676       for (i = 0; i < vec_len (fsh->free_chunks); i++)
677         {
678           c = fsh->free_chunks[i];
679           if (c == 0)
680             continue;
681
682           while (c)
683             {
684               c = c->next;
685               count++;
686             }
687         }
688       return count;
689     }
690
691   rounded_size = (1 << (max_log2 (size)));
692   fl_index = fs_free_list_for_size (rounded_size);
693
694   if (fl_index >= vec_len (fsh->free_chunks))
695     return 0;
696
697   c = fsh->free_chunks[fl_index];
698   if (c == 0)
699     return 0;
700
701   while (c)
702     {
703       c = c->next;
704       count++;
705     }
706   return count;
707 }
708
709 u8
710 fifo_segment_has_fifos (fifo_segment_t * fs)
711 {
712   return fs->h->fifos != 0;
713 }
714
715 svm_fifo_t *
716 fifo_segment_get_fifo_list (fifo_segment_t * fs)
717 {
718   return fs->h->fifos;
719 }
720
721 u8 *
722 format_fifo_segment_type (u8 * s, va_list * args)
723 {
724   fifo_segment_t *sp;
725   sp = va_arg (*args, fifo_segment_t *);
726   ssvm_segment_type_t st = ssvm_type (&sp->ssvm);
727
728   if (st == SSVM_SEGMENT_PRIVATE)
729     s = format (s, "%s", "private-heap");
730   else if (st == SSVM_SEGMENT_MEMFD)
731     s = format (s, "%s", "memfd");
732   else if (st == SSVM_SEGMENT_SHM)
733     s = format (s, "%s", "shm");
734   else
735     s = format (s, "%s", "unknown");
736   return s;
737 }
738
739 /**
740  * Segment format function
741  */
742 u8 *
743 format_fifo_segment (u8 * s, va_list * args)
744 {
745   fifo_segment_t *sp = va_arg (*args, fifo_segment_t *);
746   int verbose __attribute__ ((unused)) = va_arg (*args, int);
747   fifo_segment_header_t *fsh = sp->h;
748   u32 count, indent;
749   svm_fifo_chunk_t *c;
750   int i;
751
752   indent = format_get_indent (s) + 2;
753 #if USE_DLMALLOC == 0
754   s = format (s, "%U segment heap: %U\n", format_white_space, indent,
755               format_mheap, svm_fifo_segment_heap (sp), verbose);
756   s = format (s, "%U segment has %u active fifos\n",
757               format_white_space, indent, fifo_segment_num_fifos (sp));
758 #endif
759
760   for (i = 0; i < vec_len (fsh->free_chunks); i++)
761     {
762       c = fsh->free_chunks[i];
763       if (c == 0)
764         continue;
765       count = 0;
766       while (c)
767         {
768           c = c->next;
769           count++;
770         }
771
772       s = format (s, "%U%-5u Kb: %u free",
773                   format_white_space, indent + 2,
774                   1 << (i + max_log2 (FIFO_SEGMENT_MIN_FIFO_SIZE) - 10),
775                   count);
776     }
777   return s;
778 }
779
780 /*
781  * fd.io coding-style-patch-verification: ON
782  *
783  * Local Variables:
784  * eval: (c-set-style "gnu")
785  * End:
786  */