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