e98b58251568c9c3b3bb8ac5aec9dad30cfab7e3
[vpp.git] / src / vppinfra / vec.c
1 /*
2  * Copyright (c) 2015 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   Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #include <vppinfra/vec.h>
39 #include <vppinfra/mem.h>
40
41 /* Vector resize operator.  Called as needed by various macros such as
42    vec_add1() when we need to allocate memory. */
43 __clib_export void *
44 vec_resize_allocate_memory (void *v,
45                             word length_increment,
46                             uword data_bytes,
47                             uword header_bytes, uword data_align,
48                             uword numa_id)
49 {
50   vec_header_t *vh = _vec_find (v);
51   uword old_alloc_bytes, new_alloc_bytes;
52   void *old, *new;
53   void *oldheap;
54
55   header_bytes = vec_header_bytes (header_bytes);
56
57   data_bytes += header_bytes;
58
59   if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
60     {
61       oldheap = clib_mem_get_per_cpu_heap ();
62       clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap (numa_id));
63     }
64
65   if (!v)
66     {
67       new = clib_mem_alloc_aligned_at_offset (data_bytes, data_align, header_bytes, 1   /* yes, call os_out_of_memory */
68         );
69       new_alloc_bytes = clib_mem_size (new);
70       CLIB_MEM_UNPOISON (new + data_bytes, new_alloc_bytes - data_bytes);
71       clib_memset (new, 0, new_alloc_bytes);
72       CLIB_MEM_POISON (new + data_bytes, new_alloc_bytes - data_bytes);
73       v = new + header_bytes;
74       _vec_len (v) = length_increment;
75       _vec_numa (v) = numa_id;
76       if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
77         clib_mem_set_per_cpu_heap (oldheap);
78       return v;
79     }
80
81   vh->len += length_increment;
82   old = v - header_bytes;
83
84   /* Vector header must start heap object. */
85   ASSERT (clib_mem_is_heap_object (old));
86
87   old_alloc_bytes = clib_mem_size (old);
88
89   /* Need to resize? */
90   if (data_bytes <= old_alloc_bytes)
91     {
92       CLIB_MEM_UNPOISON (v, data_bytes);
93       if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
94         clib_mem_set_per_cpu_heap (oldheap);
95       return v;
96     }
97
98 #if CLIB_VECTOR_GROW_BY_ONE > 0
99   new_alloc_bytes = data_bytes;
100 #else
101   new_alloc_bytes = (old_alloc_bytes * 3) / 2;
102   if (new_alloc_bytes < data_bytes)
103     new_alloc_bytes = data_bytes;
104 #endif
105
106   new =
107     clib_mem_alloc_aligned_at_offset (new_alloc_bytes, data_align,
108                                       header_bytes,
109                                       1 /* yes, call os_out_of_memory */ );
110
111   /* FIXME fail gracefully. */
112   if (!new)
113     clib_panic
114       ("vec_resize fails, length increment %d, data bytes %d, alignment %d",
115        length_increment, data_bytes, data_align);
116
117   CLIB_MEM_UNPOISON (old, old_alloc_bytes);
118   clib_memcpy_fast (new, old, old_alloc_bytes);
119   clib_mem_free (old);
120
121   /* Allocator may give a bit of extra room. */
122   new_alloc_bytes = clib_mem_size (new);
123   v = new;
124
125   /* Zero new memory. */
126   CLIB_MEM_UNPOISON (new + data_bytes, new_alloc_bytes - data_bytes);
127   memset (v + old_alloc_bytes, 0, new_alloc_bytes - old_alloc_bytes);
128   CLIB_MEM_POISON (new + data_bytes, new_alloc_bytes - data_bytes);
129
130   _vec_numa ((v + header_bytes)) = numa_id;
131   if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
132     clib_mem_set_per_cpu_heap (oldheap);
133
134   return v + header_bytes;
135 }
136
137 __clib_export uword
138 clib_mem_is_vec_h (void *v, uword header_bytes)
139 {
140   return clib_mem_is_heap_object (vec_header (v, header_bytes));
141 }
142
143 __clib_export u32
144 vec_len_not_inline (void *v)
145 {
146   return vec_len (v);
147 }
148
149 __clib_export void
150 vec_free_not_inline (void *v)
151 {
152   vec_free (v);
153 }
154
155 /** \cond */
156
157 #ifdef TEST
158
159 #include <stdio.h>
160
161 void
162 main (int argc, char *argv[])
163 {
164   word n = atoi (argv[1]);
165   word i, *x = 0;
166
167   typedef struct
168   {
169     word x, y, z;
170   } FOO;
171
172   FOO *foos = vec_init (FOO, 10), *f;
173
174   vec_validate (foos, 100);
175   foos[100].x = 99;
176
177   _vec_len (foos) = 0;
178   for (i = 0; i < n; i++)
179     {
180       vec_add1 (x, i);
181       vec_add2 (foos, f, 1);
182       f->x = 2 * i;
183       f->y = 3 * i;
184       f->z = 4 * i;
185     }
186
187   {
188     word n = 2;
189     word m = 42;
190     vec_delete (foos, n, m);
191   }
192
193   {
194     word n = 2;
195     word m = 42;
196     vec_insert (foos, n, m);
197   }
198
199   vec_free (x);
200   vec_free (foos);
201   exit (0);
202 }
203 #endif
204 /** \endcond */
205
206 /*
207  * fd.io coding-style-patch-verification: ON
208  *
209  * Local Variables:
210  * eval: (c-set-style "gnu")
211  * End:
212  */