1 /*
2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif /* HAVE_CONFIG_H */
25 #ifdef __POCC__
26 #include <sys/types.h>
27 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #ifndef NO_STRING_H
32 #include <string.h>
33 #else
34 #include <strings.h>
35 #endif
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif /* HAVE_UNISTD_H */
40
41 #include "timidity.h"
42 #include "common.h"
43 #include "mblock.h"
44
45 static MBlockNode *free_mblock_list = NULL;
46 #define ADDRALIGN 8
47 /* #define DEBUG */
48
init_mblock(MBlockList * mblock)49 void init_mblock(MBlockList *mblock)
50 {
51 mblock->first = NULL;
52 mblock->allocated = 0;
53 }
54
new_mblock_node(size_t n)55 static MBlockNode *new_mblock_node(size_t n)
56 {
57 MBlockNode *p;
58
59 if(n > MIN_MBLOCK_SIZE)
60 {
61 if((p = (MBlockNode *)safe_malloc(n + sizeof(MBlockNode))) == NULL)
62 return NULL;
63 p->block_size = n;
64 }
65 else if(free_mblock_list == NULL)
66 {
67 if((p = (MBlockNode *)safe_malloc(sizeof(MBlockNode)
68 + MIN_MBLOCK_SIZE)) == NULL)
69 return NULL;
70 p->block_size = MIN_MBLOCK_SIZE;
71 }
72 else
73 {
74 p = free_mblock_list;
75 free_mblock_list = free_mblock_list->next;
76 }
77
78 p->offset = 0;
79 p->next = NULL;
80
81 return p;
82 }
83
enough_block_memory(MBlockList * mblock,size_t n)84 static int enough_block_memory(MBlockList *mblock, size_t n)
85 {
86 size_t newoffset;
87
88 if(mblock->first == NULL)
89 return 0;
90
91 newoffset = mblock->first->offset + n;
92
93 if(newoffset < mblock->first->offset) /* exceed representable in size_t */
94 return 0;
95
96 if(newoffset > mblock->first->block_size)
97 return 0;
98
99 return 1;
100 }
101
new_segment(MBlockList * mblock,size_t nbytes)102 void *new_segment(MBlockList *mblock, size_t nbytes)
103 {
104 MBlockNode *p;
105 void *addr;
106
107 /* round up to ADDRALIGN */
108 nbytes = ((nbytes + ADDRALIGN - 1) & ~(ADDRALIGN - 1));
109 if(!enough_block_memory(mblock, nbytes))
110 {
111 p = new_mblock_node(nbytes);
112 p->next = mblock->first;
113 mblock->first = p;
114 mblock->allocated += p->block_size;
115 }
116 else
117 p = mblock->first;
118
119 addr = (void *)(p->buffer + p->offset);
120 p->offset += nbytes;
121
122 #ifdef DEBUG
123 if(((unsigned long)addr) & (ADDRALIGN-1))
124 {
125 fprintf(stderr, "Bad address: 0x%x\n", addr);
126 exit(1);
127 }
128 #endif /* DEBUG */
129
130 return addr;
131 }
132
reuse_mblock1(MBlockNode * p)133 static void reuse_mblock1(MBlockNode *p)
134 {
135 if(p->block_size > MIN_MBLOCK_SIZE)
136 free(p);
137 else /* p->block_size <= MIN_MBLOCK_SIZE */
138 {
139 p->next = free_mblock_list;
140 free_mblock_list = p;
141 }
142 }
143
reuse_mblock(MBlockList * mblock)144 void reuse_mblock(MBlockList *mblock)
145 {
146 MBlockNode *p;
147
148 if((p = mblock->first) == NULL)
149 return; /* There is nothing to collect memory */
150
151 while(p)
152 {
153 MBlockNode *tmp;
154
155 tmp = p;
156 p = p->next;
157 reuse_mblock1(tmp);
158 }
159 init_mblock(mblock);
160 }
161
strdup_mblock(MBlockList * mblock,const char * str)162 char *strdup_mblock(MBlockList *mblock, const char *str)
163 {
164 int len;
165 char *p;
166
167 len = strlen(str);
168 p = (char *)new_segment(mblock, len + 1); /* for '\0' */
169 memcpy(p, str, len + 1);
170 return p;
171 }
172
free_global_mblock(void)173 int free_global_mblock(void)
174 {
175 int cnt;
176
177 cnt = 0;
178 while(free_mblock_list)
179 {
180 MBlockNode *tmp;
181
182 tmp = free_mblock_list;
183 free_mblock_list = free_mblock_list->next;
184 free(tmp);
185 cnt++;
186 }
187 return cnt;
188 }
189