+static inline int
+sm_lookup_segment_and_alloc_fifos (segment_manager_t *sm,
+ segment_manager_props_t *props,
+ u32 thread_index, svm_fifo_t **rx_fifo,
+ svm_fifo_t **tx_fifo)
+{
+ uword free_bytes, max_free_bytes;
+ fifo_segment_t *cur, *fs = 0;
+
+ max_free_bytes = props->rx_fifo_size + props->tx_fifo_size - 1;
+
+ pool_foreach (cur, sm->segments)
+ {
+ if (fifo_segment_flags (cur) & FIFO_SEGMENT_F_CUSTOM_USE)
+ continue;
+ free_bytes = fifo_segment_available_bytes (cur);
+ if (free_bytes > max_free_bytes)
+ {
+ max_free_bytes = free_bytes;
+ fs = cur;
+ }
+ }
+
+ if (PREDICT_FALSE (!fs))
+ return SESSION_E_SEG_NO_SPACE;
+
+ return segment_manager_try_alloc_fifos (
+ fs, thread_index, props->rx_fifo_size, props->tx_fifo_size, rx_fifo,
+ tx_fifo);
+}
+
+static int
+sm_lock_and_alloc_segment_and_fifos (segment_manager_t *sm,
+ segment_manager_props_t *props,
+ u32 thread_index, svm_fifo_t **rx_fifo,
+ svm_fifo_t **tx_fifo)
+{
+ int new_fs_index, rv;
+ fifo_segment_t *fs;
+
+ if (!props->add_segment)
+ return SESSION_E_SEG_NO_SPACE;
+
+ clib_rwlock_writer_lock (&sm->segments_rwlock);
+
+ /* Make sure there really is no free space. Another worker might've freed
+ * some fifos or allocated a segment */
+ rv = sm_lookup_segment_and_alloc_fifos (sm, props, thread_index, rx_fifo,
+ tx_fifo);
+ if (!rv)
+ goto done;
+
+ new_fs_index =
+ segment_manager_add_segment (sm, 0 /* segment_size*/, 1 /* notify_app */);
+ if (new_fs_index < 0)
+ {
+ rv = SESSION_E_SEG_CREATE;
+ goto done;
+ }
+ fs = segment_manager_get_segment (sm, new_fs_index);
+ rv = segment_manager_try_alloc_fifos (fs, thread_index, props->rx_fifo_size,
+ props->tx_fifo_size, rx_fifo, tx_fifo);
+ if (rv)
+ {
+ SESSION_DBG ("Added a segment, still can't allocate a fifo");
+ rv = SESSION_E_SEG_NO_SPACE2;
+ goto done;
+ }
+
+done:
+
+ clib_rwlock_writer_unlock (&sm->segments_rwlock);
+
+ return rv;
+}
+