Contiki 2.5
mmem.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * @(#)$Id: mmem.c,v 1.2 2006/12/22 17:14:06 barner Exp $
32  */
33 
34 /**
35  * \addtogroup mmem
36  * @{
37  */
38 
39 /**
40  * \file
41  * Implementation of the managed memory allocator
42  * \author
43  * Adam Dunkels <adam@sics.se>
44  *
45  */
46 
47 
48 #include "mmem.h"
49 #include "list.h"
50 #include "contiki-conf.h"
51 #include <string.h>
52 #include "profiling.h"
53 
54 #define DEBUG 0
55 #if DEBUG
56 #include <stdio.h>
57 #define PRINTF(...) printf(__VA_ARGS__)
58 #else
59 #define PRINTF(...)
60 #endif
61 
62 #ifdef MMEM_CONF_SIZE
63 #define MMEM_SIZE MMEM_CONF_SIZE
64 #else
65 #define MMEM_SIZE 4096
66 #endif
67 
68 #ifdef MMEM_CONF_ALIGNMENT
69 #define MMEM_ALIGNMENT MMEM_CONF_ALIGNMENT
70 #else
71 #define MMEM_ALIGNMENT 2
72 #endif
73 
74 LIST(mmemlist);
75 unsigned int avail_memory;
76 static char memory[MMEM_SIZE];
77 
78 /*---------------------------------------------------------------------------*/
79 /**
80  * \brief Allocate a managed memory block
81  * \param m A pointer to a struct mmem.
82  * \param size The size of the requested memory block
83  * \return Non-zero if the memory could be allocated, zero if memory
84  * was not available.
85  * \author Adam Dunkels
86  *
87  * This function allocates a chunk of managed memory. The
88  * memory allocated with this function must be deallocated
89  * using the mmem_free() function.
90  *
91  * \note This function does NOT return a pointer to the
92  * allocated memory, but a pointer to a structure that
93  * contains information about the managed memory. The
94  * macro MMEM_PTR() is used to get a pointer to the
95  * allocated memory.
96  *
97  */
98 int
99 mmem_alloc(struct mmem *m, unsigned int size)
100 {
101  /* Check if we have enough memory left for this allocation. */
102  if((avail_memory < size) ) {
103  PRINTF("MMEM: %u < %u\n",avail_memory,size);
104  return 0;
105  }
106  if (avail_memory> MMEM_SIZE){
107  PRINTF("MMEM: %u > %u\n",avail_memory,MMEM_SIZE);
108  return 0;
109  }
110 
111 
112  /* We had enough memory so we add this memory block to the end of
113  the list of allocated memory blocks. */
114  list_add(mmemlist, m);
115 
116  /* Set up the pointer so that it points to the first available byte
117  in the memory block. */
118  m->ptr = &memory[MMEM_SIZE - avail_memory];
119  /* Remember the size of this memory block. */
120  m->size = size;
121  m->real_size = size;
122 
123  while( m->real_size % MMEM_ALIGNMENT != 0 ) {
124  m->real_size ++;
125  }
126 
127  /* Decrease the amount of available memory. */
128  avail_memory -= m->real_size;
129  /* Return non-zero to indicate that we were able to allocate
130  memory. */
131  return 1;
132 }
133 /*---------------------------------------------------------------------------*/
134 /**
135  * \brief Deallocate a managed memory block
136  * \param m A pointer to the managed memory block
137  * \author Adam Dunkels
138  *
139  * This function deallocates a managed memory block that
140  * previously has been allocated with mmem_alloc().
141  *
142  */
143 void
144 mmem_free(struct mmem *m)
145 {
146  if(m->real_size > MMEM_SIZE - avail_memory){
147  PRINTF("MMEM: too much free %u\n", m->real_size);
148  return;
149  }
150  struct mmem *n;
151  if(m->next != NULL) {
152  /* Compact the memory after the allocation that is to be removed
153  by moving it downwards. */
154  memmove(m->ptr, m->next->ptr,
155  &memory[MMEM_SIZE - avail_memory] - (char *)m->next->ptr);
156 
157  /* Update all the memory pointers that points to memory that is
158  after the allocation that is to be removed. */
159  for(n = m->next; n != NULL; n = n->next) {
160  n->ptr = (void *)((char *)n->ptr - m->real_size);
161  }
162  }
163 
164  avail_memory += m->real_size;
165 // PRINTF("MMEM: free %u\n",avail_memory);
166 
167  /* Remove the memory block from the list. */
168  list_remove(mmemlist, m);
169 }
170 
171 /*---------------------------------------------------------------------------*/
172 /**
173  * \brief Change the size of allocated memory
174  * \param mem mmem chunk whose size should be changed
175  * \param size Size to change the chunk to
176  * \return 1 on success, 0 on failure
177  * \author Daniel Willmann
178  *
179  * This function is the mmem equivalent of realloc(). If the size
180  * could not be changed the original chunk is preserved.
181  */
182 int
183 mmem_realloc(struct mmem *mem, unsigned int size)
184 {
185  int mysize = size;
186 
187  while( mysize % MMEM_ALIGNMENT != 0 ) {
188  mysize ++;
189  }
190 
191  int diff = (int)mysize - mem->real_size;
192 
193  /* Already the correct size */
194  if (diff == 0)
195  return 1;
196 
197  /* Check if request is to big */
198  if (diff > 0 && diff > avail_memory) {
199  PRINTF("MMEM: realloc failed (diff: %i, avail: %u\n", diff, avail_memory);
200  return 0;
201  }
202 
203  /* We need to do the same thing as in mmem_free */
204  struct mmem *n;
205  if (mem->next != NULL) {
206  memmove((char *)mem->next->ptr+diff, (char *)mem->next->ptr,
207  &memory[MMEM_SIZE - avail_memory] - (char *)mem->next->ptr);
208 
209  /* Update all the memory pointers that points to memory that is
210  after the allocation that is to be moved. */
211  for(n = mem->next; n != NULL; n = n->next) {
212  n->ptr = (void *)((char *)n->ptr + diff);
213  }
214  }
215 
216  mem->size = size;
217  mem->real_size = mysize;
218  avail_memory -= diff;
219  return 1;
220 }
221 
222 /*---------------------------------------------------------------------------*/
223 /**
224  * \brief Assign a chunk of memory form one mem struct to another
225  * \param m_old Old mmem struct that contains the memory
226  * \param m_new New mmem struct that will contain the memory after this call
227  * \author Daniel Willmann
228  *
229  * This function is needed as mmem expects the mmem structs to be
230  * in the same order as the chunks of memory are. The new struct
231  * will be inserted into mmem's internal list at the same place
232  * the old one was.
233  */
234 void
235 mmem_reparent(struct mmem *m_old, struct mmem *m_new)
236 {
237  m_new->ptr = m_old->ptr;
238  list_insert(mmemlist, m_old, m_new);
239  list_remove(mmemlist, m_old);
240  m_old->size = 0;
241  m_old->real_size = 0;
242 }
243 
244 /*---------------------------------------------------------------------------*/
245 /**
246  * \brief Initialize the managed memory module
247  * \author Adam Dunkels
248  *
249  * This function initializes the managed memory module and
250  * should be called before any other function from the
251  * module.
252  *
253  */
254 void
256 {
257  static int inited = 0;
258  if (inited) {
259  PRINTF("Duplicate init\n");
260  return;
261  }
262  list_init(mmemlist);
263  avail_memory = MMEM_SIZE;
264  inited = 1;
265 }
266 /*---------------------------------------------------------------------------*/
267 
268 /** @} */