aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-03-14 00:07:51 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-03-14 00:07:51 +0000
commit75605788ff6be5a766a7e41da583d5e8f47d9ac4 (patch)
tree36853bddc7322d7a30c3dab2f064b8da7efe481e
parent07766bb0e7adcefa5dd5a373986176a5cd42ed23 (diff)
downloadbusybox-w32-75605788ff6be5a766a7e41da583d5e8f47d9ac4.tar.gz
busybox-w32-75605788ff6be5a766a7e41da583d5e8f47d9ac4.tar.bz2
busybox-w32-75605788ff6be5a766a7e41da583d5e8f47d9ac4.zip
gzip: use common bbunzip infrastructure - ~700 bytes code less
-rw-r--r--archival/Kbuild2
-rw-r--r--archival/bbunzip.c23
-rw-r--r--archival/gzip.c171
-rw-r--r--docs/keep_data_small.txt88
4 files changed, 185 insertions, 99 deletions
diff --git a/archival/Kbuild b/archival/Kbuild
index 011feee5f..07b442f15 100644
--- a/archival/Kbuild
+++ b/archival/Kbuild
@@ -14,7 +14,7 @@ lib-$(CONFIG_CPIO) += cpio.o
14lib-$(CONFIG_DPKG) += dpkg.o 14lib-$(CONFIG_DPKG) += dpkg.o
15lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o 15lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o
16lib-$(CONFIG_GUNZIP) += bbunzip.o 16lib-$(CONFIG_GUNZIP) += bbunzip.o
17lib-$(CONFIG_GZIP) += gzip.o 17lib-$(CONFIG_GZIP) += gzip.o bbunzip.o
18lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o 18lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o
19lib-$(CONFIG_RPM) += rpm.o 19lib-$(CONFIG_RPM) += rpm.o
20lib-$(CONFIG_TAR) += tar.o 20lib-$(CONFIG_TAR) += tar.o
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index f7c861256..e16e6b083 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -9,12 +9,12 @@
9#include "unarchive.h" 9#include "unarchive.h"
10 10
11enum { 11enum {
12 OPT_STDOUT = 1, 12 OPT_STDOUT = 0x1,
13 OPT_FORCE = 2, 13 OPT_FORCE = 0x2,
14/* gunzip only: */ 14/* gunzip only: */
15 OPT_TEST = 4, 15 OPT_VERBOSE = 0x4,
16 OPT_DECOMPRESS = 8, 16 OPT_DECOMPRESS = 0x8,
17 OPT_VERBOSE = 0x10, 17 OPT_TEST = 0x10,
18}; 18};
19 19
20static 20static
@@ -33,8 +33,7 @@ int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
33 return 0; 33 return 0;
34} 34}
35 35
36static 36int bbunpack(char **argv,
37int unpack(char **argv,
38 char* (*make_new_name)(char *filename), 37 char* (*make_new_name)(char *filename),
39 USE_DESKTOP(long long) int (*unpacker)(void) 38 USE_DESKTOP(long long) int (*unpacker)(void)
40) 39)
@@ -173,7 +172,7 @@ int bunzip2_main(int argc, char **argv)
173 if (applet_name[2] == 'c') 172 if (applet_name[2] == 'c')
174 option_mask32 |= OPT_STDOUT; 173 option_mask32 |= OPT_STDOUT;
175 174
176 return unpack(argv, make_new_name_bunzip2, unpack_bunzip2); 175 return bbunpack(argv, make_new_name_bunzip2, unpack_bunzip2);
177} 176}
178 177
179#endif 178#endif
@@ -267,13 +266,13 @@ USE_DESKTOP(long long) int unpack_gunzip(void)
267int gunzip_main(int argc, char **argv); 266int gunzip_main(int argc, char **argv);
268int gunzip_main(int argc, char **argv) 267int gunzip_main(int argc, char **argv)
269{ 268{
270 getopt32(argc, argv, "cftdv"); 269 getopt32(argc, argv, "cfvdt");
271 argv += optind; 270 argv += optind;
272 /* if called as zcat */ 271 /* if called as zcat */
273 if (applet_name[1] == 'c') 272 if (applet_name[1] == 'c')
274 option_mask32 |= OPT_STDOUT; 273 option_mask32 |= OPT_STDOUT;
275 274
276 return unpack(argv, make_new_name_gunzip, unpack_gunzip); 275 return bbunpack(argv, make_new_name_gunzip, unpack_gunzip);
277} 276}
278 277
279#endif 278#endif
@@ -311,7 +310,7 @@ int unlzma_main(int argc, char **argv)
311 if (applet_name[4] == 'c') 310 if (applet_name[4] == 'c')
312 option_mask32 |= OPT_STDOUT; 311 option_mask32 |= OPT_STDOUT;
313 312
314 return unpack(argv, make_new_name_unlzma, unpack_unlzma); 313 return bbunpack(argv, make_new_name_unlzma, unpack_unlzma);
315} 314}
316 315
317#endif 316#endif
@@ -350,7 +349,7 @@ int uncompress_main(int argc, char **argv)
350 getopt32(argc, argv, "cf"); 349 getopt32(argc, argv, "cf");
351 argv += optind; 350 argv += optind;
352 351
353 return unpack(argv, make_new_name_uncompress, unpack_uncompress); 352 return bbunpack(argv, make_new_name_uncompress, unpack_uncompress);
354} 353}
355 354
356#endif 355#endif
diff --git a/archival/gzip.c b/archival/gzip.c
index c8444ac25..90075272d 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -2074,6 +2074,7 @@ static void zip(int in, int out)
2074 2074
2075 2075
2076/* ======================================================================== */ 2076/* ======================================================================== */
2077#if 0
2077static void abort_gzip(int ATTRIBUTE_UNUSED ignored) 2078static void abort_gzip(int ATTRIBUTE_UNUSED ignored)
2078{ 2079{
2079 exit(1); 2080 exit(1);
@@ -2082,92 +2083,6 @@ static void abort_gzip(int ATTRIBUTE_UNUSED ignored)
2082int gzip_main(int argc, char **argv); 2083int gzip_main(int argc, char **argv);
2083int gzip_main(int argc, char **argv) 2084int gzip_main(int argc, char **argv)
2084{ 2085{
2085 enum {
2086 OPT_tostdout = 0x1,
2087 OPT_force = 0x2,
2088 };
2089
2090 unsigned opt;
2091 int inFileNum;
2092 int outFileNum;
2093 int i;
2094 struct stat statBuf;
2095
2096 opt = getopt32(argc, argv, "cf123456789qv" USE_GUNZIP("d"));
2097 //if (opt & 0x1) // -c
2098 //if (opt & 0x2) // -f
2099 /* Ignore 1-9 (compression level) options */
2100 //if (opt & 0x4) // -1
2101 //if (opt & 0x8) // -2
2102 //if (opt & 0x10) // -3
2103 //if (opt & 0x20) // -4
2104 //if (opt & 0x40) // -5
2105 //if (opt & 0x80) // -6
2106 //if (opt & 0x100) // -7
2107 //if (opt & 0x200) // -8
2108 //if (opt & 0x400) // -9
2109 //if (opt & 0x800) // -q
2110 //if (opt & 0x1000) // -v
2111#if ENABLE_GUNZIP /* gunzip_main may not be visible... */
2112 if (opt & 0x2000) { // -d
2113 /* FIXME: getopt32 should not depend on optind */
2114 optind = 1;
2115 return gunzip_main(argc, argv);
2116 }
2117#endif
2118
2119 /* Comment?? */
2120 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
2121 signal(SIGINT, abort_gzip);
2122 }
2123#ifdef SIGTERM
2124 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
2125 signal(SIGTERM, abort_gzip);
2126 }
2127#endif
2128#ifdef SIGHUP
2129 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
2130 signal(SIGHUP, abort_gzip);
2131 }
2132#endif
2133
2134 ptr_to_globals = xzalloc(sizeof(struct global1) + sizeof(struct global2));
2135 ptr_to_globals++;
2136 G2.l_desc.dyn_tree = G2.dyn_ltree;
2137 G2.l_desc.static_tree = G2.static_ltree;
2138 G2.l_desc.extra_bits = extra_lbits;
2139 G2.l_desc.extra_base = LITERALS + 1;
2140 G2.l_desc.elems = L_CODES;
2141 G2.l_desc.max_length = MAX_BITS;
2142 //G2.l_desc.max_code = 0;
2143
2144 G2.d_desc.dyn_tree = G2.dyn_dtree;
2145 G2.d_desc.static_tree = G2.static_dtree;
2146 G2.d_desc.extra_bits = extra_dbits;
2147 //G2.d_desc.extra_base = 0;
2148 G2.d_desc.elems = D_CODES;
2149 G2.d_desc.max_length = MAX_BITS;
2150 //G2.d_desc.max_code = 0;
2151
2152 G2.bl_desc.dyn_tree = G2.bl_tree;
2153 //G2.bl_desc.static_tree = NULL;
2154 G2.bl_desc.extra_bits = extra_blbits,
2155 //G2.bl_desc.extra_base = 0;
2156 G2.bl_desc.elems = BL_CODES;
2157 G2.bl_desc.max_length = MAX_BL_BITS;
2158 //G2.bl_desc.max_code = 0;
2159
2160 /* Allocate all global buffers (for DYN_ALLOC option) */
2161 ALLOC(uch, G1.l_buf, INBUFSIZ);
2162 ALLOC(uch, G1.outbuf, OUTBUFSIZ);
2163 ALLOC(ush, G1.d_buf, DIST_BUFSIZE);
2164 ALLOC(uch, G1.window, 2L * WSIZE);
2165 ALLOC(ush, G1.prev, 1L << BITS);
2166
2167 /* Initialise the CRC32 table */
2168 G1.crc_32_tab = crc32_filltable(0);
2169
2170 clear_bufs();
2171 2086
2172 if (optind == argc) { 2087 if (optind == argc) {
2173 G1.time_stamp = 0; 2088 G1.time_stamp = 0;
@@ -2240,3 +2155,87 @@ int gzip_main(int argc, char **argv)
2240 2155
2241 return 0; //##G1.exit_code; 2156 return 0; //##G1.exit_code;
2242} 2157}
2158#endif
2159
2160int bbunpack(char **argv,
2161 char* (*make_new_name)(char *filename),
2162 USE_DESKTOP(long long) int (*unpacker)(void)
2163);
2164
2165static
2166char* make_new_name_gzip(char *filename)
2167{
2168 return xasprintf("%s.gz", filename);
2169}
2170
2171static
2172USE_DESKTOP(long long) int pack_gzip(void)
2173{
2174 struct stat s;
2175
2176 G1.time_stamp = 0;
2177 if (!fstat(STDIN_FILENO, &s))
2178 G1.time_stamp = s.st_ctime;
2179 zip(STDIN_FILENO, STDOUT_FILENO);
2180 return 0;
2181}
2182
2183int gzip_main(int argc, char **argv);
2184int gzip_main(int argc, char **argv)
2185{
2186 unsigned opt;
2187
2188 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
2189 opt = getopt32(argc, argv, "cfv" USE_GUNZIP("d") "q123456789" );
2190 option_mask32 &= 0x7; /* Clear -d, ignore -q, -0..9 */
2191 //if (opt & 0x1) // -c
2192 //if (opt & 0x2) // -f
2193 //if (opt & 0x4) // -v
2194#if ENABLE_GUNZIP /* gunzip_main may not be visible... */
2195 if (opt & 0x8) { // -d
2196 /* FIXME: getopt32 should not depend on optind */
2197 optind = 1;
2198 return gunzip_main(argc, argv);
2199 }
2200#endif
2201
2202 ptr_to_globals = xzalloc(sizeof(struct global1) + sizeof(struct global2));
2203 ptr_to_globals++;
2204 G2.l_desc.dyn_tree = G2.dyn_ltree;
2205 G2.l_desc.static_tree = G2.static_ltree;
2206 G2.l_desc.extra_bits = extra_lbits;
2207 G2.l_desc.extra_base = LITERALS + 1;
2208 G2.l_desc.elems = L_CODES;
2209 G2.l_desc.max_length = MAX_BITS;
2210 //G2.l_desc.max_code = 0;
2211
2212 G2.d_desc.dyn_tree = G2.dyn_dtree;
2213 G2.d_desc.static_tree = G2.static_dtree;
2214 G2.d_desc.extra_bits = extra_dbits;
2215 //G2.d_desc.extra_base = 0;
2216 G2.d_desc.elems = D_CODES;
2217 G2.d_desc.max_length = MAX_BITS;
2218 //G2.d_desc.max_code = 0;
2219
2220 G2.bl_desc.dyn_tree = G2.bl_tree;
2221 //G2.bl_desc.static_tree = NULL;
2222 G2.bl_desc.extra_bits = extra_blbits,
2223 //G2.bl_desc.extra_base = 0;
2224 G2.bl_desc.elems = BL_CODES;
2225 G2.bl_desc.max_length = MAX_BL_BITS;
2226 //G2.bl_desc.max_code = 0;
2227
2228 /* Allocate all global buffers (for DYN_ALLOC option) */
2229 ALLOC(uch, G1.l_buf, INBUFSIZ);
2230 ALLOC(uch, G1.outbuf, OUTBUFSIZ);
2231 ALLOC(ush, G1.d_buf, DIST_BUFSIZE);
2232 ALLOC(uch, G1.window, 2L * WSIZE);
2233 ALLOC(ush, G1.prev, 1L << BITS);
2234
2235 /* Initialise the CRC32 table */
2236 G1.crc_32_tab = crc32_filltable(0);
2237
2238 clear_bufs();
2239
2240 return bbunpack(argv, make_new_name_gzip, pack_gzip);
2241}
diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt
new file mode 100644
index 000000000..88cc2bc66
--- /dev/null
+++ b/docs/keep_data_small.txt
@@ -0,0 +1,88 @@
1 Keeping data small
2
3When many applets are compiled into busybox, all rw data and
4bss for each applet are concatenated. Including those from libc,
5if static bbox is built. When bbox is started, _all_ this data
6is allocated, not just that one part for selected applet.
7
8What "allocated" exactly means, depends on arch.
9On nommu it's probably bites the most, actually using real
10RAM for rwdata and bss. On i386, bss is lazily allocated
11by COWed zero pages. Not sure about rwdata - also COW?
12
13Small experiment measures "parasitic" bbox memory consumption.
14Here we start 1000 "busybox sleep 10" in parallel.
15bbox binary is practically allyesconfig static one,
16built against uclibc:
17
18bash-3.2# nmeter '%t %c %b %m %p %[pn]'
1923:17:28 .......... 0 0 168M 0 147
2023:17:29 .......... 0 0 168M 0 147
2123:17:30 U......... 0 0 168M 1 147
2223:17:31 SU........ 0 188k 181M 244 391
2323:17:32 SSSSUUU... 0 0 223M 757 1147
2423:17:33 UUU....... 0 0 223M 0 1147
2523:17:34 U......... 0 0 223M 1 1147
2623:17:35 .......... 0 0 223M 0 1147
2723:17:36 .......... 0 0 223M 0 1147
2823:17:37 S......... 0 0 223M 0 1147
2923:17:38 .......... 0 0 223M 1 1147
3023:17:39 .......... 0 0 223M 0 1147
3123:17:40 .......... 0 0 223M 0 1147
3223:17:41 .......... 0 0 210M 0 906
3323:17:42 .......... 0 0 168M 1 147
3423:17:43 .......... 0 0 168M 0 147
35
36This requires 55M of memory. Thus 1 trivial busybox applet
37takes 55k of userspace memory (nmeter doesn't account for kernel-side
38allocations). Definitely can be improved.
39
40Thus we should avoid large global data in our applets,
41and should minimize usage of libc functions which implicitly use
42such structures in libc.
43
44 Example 1
45
46One example how to reduce global data usage is in
47archival/libunarchive/decompress_unzip.c:
48
49/* This is somewhat complex-looking arrangement, but it allows
50 * to place decompressor state either in bss or in
51 * malloc'ed space simply by changing #defines below.
52 * Sizes on i386:
53 * text data bss dec hex
54 * 5256 0 108 5364 14f4 - bss
55 * 4915 0 0 4915 1333 - malloc
56 */
57#define STATE_IN_BSS 0
58#define STATE_IN_MALLOC 1
59
60This example completely eliminates globals in that module.
61Required memory is allocated in inflate_gunzip() [its main module]
62and then passed down to all subroutines which need to access globals
63as a parameter.
64
65 Example 2
66
67In case you don't want to pass this additional parameter everywhere,
68take a look at archival/gzip.c. Here all global data is replaced by
69singe global pointer (ptr_to_globals) to allocated storage.
70
71In order to not duplicate ptr_to_globals in every applet, you can
72reuse single common one. It is defined in libbb/messages.c
73as void *ptr_to_globals, but is NOT declared in libbb.h.
74You first define a struct:
75
76struct my_globals { int a; char buf[1000]; };
77
78and then declare that ptr_to_globals is a pointer to it:
79
80extern struct my_globals *ptr_to_globals;
81#define G (*ptr_to_globals)
82
83Linker magic enures that these two merge into single pointer object.
84Now initialize it in <applet>_main():
85
86 ptr_to_globals = xzalloc(sizeof(G));
87
88and you can reference "globals" by G.a, G.buf and so on, in any function.