apps/system/lzf:

- The maximum block size is now configuration setting in order to give finer control over memory usage.
  - The compression/decompression buffers have been moved out the stack and are now global variables.  This eliminates the need to set large stack sizes to use this utility.
  - Added semaphore protection of all global variables for the case of the FLAT or PROTECTED builds.  Unlike the KERNEL build, the same global variables will be used by each instance of the LZF utility.  If you want thread safety, then you must either (a) serialize all access to the global variables, or (b) pack the global variables into a structure and allocate that structure on each execution of lzf_main().
This commit is contained in:
Gregory Nutt 2018-03-17 15:35:19 -06:00
parent de248dd952
commit d35a3e847e
2 changed files with 91 additions and 41 deletions

View File

@ -12,6 +12,23 @@ config SYSTEM_LZF
if SYSTEM_LZF
config SYSTEM_LZF_BLOG
int "Log2 of block size"
default 10
range 9 12
---help---
This example uses two buffers of size a little more than
(1 << CONFIG_SYSTEM_LZF_BLOG) to compress and decompress data in
chunks. Slightly better compression should be obtainable with larger
chunks.
NOTE: This is a static memory allocation and will take add a little
more than 2 * (1 << CONFIG_SYSTEM_LZF_BLOG) bytes to the size of the
.bss section used by the program.
NOTE: This represents a maximum blocksize. The use may select a
smaller blocksize using the 'lzf -b' option.
config SYSTEM_LZF_PROGNAME
string "Program name"
default "lzf"

View File

@ -1,5 +1,5 @@
/****************************************************************************
* apps/exmaples/lzf/lxf_main.c
* apps/exmaples/lzf/lzf_main.c
*
* Copyright (c) 2006 Stefan Traby <stefan@hello-penguin.com>
*
@ -41,6 +41,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
#include <getopt.h>
#include <errno.h>
#include <limits.h>
@ -50,13 +51,17 @@
* Pre-processor Definitions
****************************************************************************/
#define BLOCKSIZE (512 - 1)
#define BLOCKSIZE ((1 << CONFIG_SYSTEM_LZF_BLOG) - 1)
#define MAX_BLOCKSIZE BLOCKSIZE
/****************************************************************************
* Private Data
****************************************************************************/
#ifndef CONFIG_BUILD_KERNEL
static sem_t g_exclsem = SEM_INITIALIZER(1);
#endif
static off_t g_nread;
static off_t g_nwritten;
@ -64,22 +69,26 @@ static FAR const char *g_imagename;
static enum { COMPRESS, UNCOMPRESS } g_mode;
static bool g_verbose;
static bool g_force;
static long blocksize;
static unsigned long g_blocksize;
static lzf_state_t g_htab;
static FAR const char *opt =
"-c compress\n"
"-d decompress\n"
"-f force overwrite of output file\n"
"-h give this help\n"
"-v verbose mode\n"
"-b # set blocksize\n"
"\n";
static uint8_t g_buf1[MAX_BLOCKSIZE + LZF_MAX_HDR_SIZE + 16];
static uint8_t g_buf2[MAX_BLOCKSIZE + LZF_MAX_HDR_SIZE + 16];
/****************************************************************************
* Private Functions
****************************************************************************/
#ifndef CONFIG_BUILD_KERNEL
static void lzf_exit(int exitcode) noreturn_function;
static void lzf_exit(int exitcode)
{
(void)sem_post(&g_exclsem);
exit(exitcode);
}
#else
# define lzf_exit(c) exit(c)
#endif
static void usage(int ret)
{
fprintf(stderr, "\n"
@ -87,11 +96,16 @@ static void usage(int ret)
"uses liblzf written by Marc Lehmann <schmorp@schmorp.de> You can find more info at\n"
"http://liblzf.plan9.de/\n"
"\n"
"usage: lzf [-dufhvb] [file ...]\n"
"\n%s",
opt);
"usage: lzf [-dufhvb] [file ...]\n\n"
"-c Compress\n"
"-d Decompress\n"
"-f Force overwrite of output file\n"
"-h Give this help\n"
"-v Verbose mode\n"
"-b # Set blocksize (max %lu)\n"
"\n", (unsigned long)MAX_BLOCKSIZE);
exit(ret);
lzf_exit(ret);
}
static inline ssize_t rread(int fd, FAR void *buf, size_t len)
@ -153,14 +167,12 @@ static int compress_fd(int from, int to)
{
ssize_t us;
ssize_t len;
uint8_t buf1[MAX_BLOCKSIZE + LZF_MAX_HDR_SIZE + 16];
uint8_t buf2[MAX_BLOCKSIZE + LZF_MAX_HDR_SIZE + 16];
uint8_t *header;
g_nread = g_nwritten = 0;
while ((us = rread(from, &buf1[LZF_MAX_HDR_SIZE], blocksize)) > 0)
while ((us = rread(from, &g_buf1[LZF_MAX_HDR_SIZE], g_blocksize)) > 0)
{
len = lzf_compress(&buf1[LZF_MAX_HDR_SIZE], us, &buf2[LZF_MAX_HDR_SIZE],
len = lzf_compress(&g_buf1[LZF_MAX_HDR_SIZE], us, &g_buf2[LZF_MAX_HDR_SIZE],
us > 4 ? us - 4 : us, g_htab, &header);
if (wwrite(to, header, len) == -1)
{
@ -174,8 +186,6 @@ static int compress_fd(int from, int to)
static int uncompress_fd(int from, int to)
{
uint8_t header[LZF_MAX_HDR_SIZE];
uint8_t buf1[MAX_BLOCKSIZE + LZF_MAX_HDR_SIZE + 16];
uint8_t buf2[MAX_BLOCKSIZE + LZF_MAX_HDR_SIZE + 16];
FAR uint8_t *p;
int l;
int rd;
@ -238,7 +248,7 @@ static int uncompress_fd(int from, int to)
if (l > 0)
{
memcpy(buf1, p, l);
memcpy(g_buf1, p, l);
}
if (l > bytes)
@ -247,7 +257,7 @@ static int uncompress_fd(int from, int to)
memmove(header, &p[bytes], over);
}
p = &buf1[l];
p = &g_buf1[l];
rd = bytes - l;
if (rd > 0)
{
@ -259,21 +269,21 @@ static int uncompress_fd(int from, int to)
if (cs == -1)
{
if (wwrite (to, buf1, us))
if (wwrite (to, g_buf1, us))
{
return -1;
}
}
else
{
if (lzf_decompress(buf1, cs, buf2, us) != us)
if (lzf_decompress(g_buf1, cs, g_buf2, us) != us)
{
fprintf(stderr, "%s: decompress: invalid stream - data corrupted\n",
g_imagename);
return -1;
}
if (wwrite(to, buf2, us))
if (wwrite(to, g_buf2, us))
{
return -1;
}
@ -433,12 +443,35 @@ int lzf_main(int argc, FAR char *argv[])
int optc;
int ret = 0;
#ifndef CONFIG_BUILD_KERNEL
/* Get exclusive access to the global variables. Global variables are
* used because the hash table and buffers are too large to allocate on
* the embedded stack. But the use of global variables has the downside
* or forcing serialization of this logic in order to work in a multi-
* tasking environment.
*
* REVISIT: An alternative would be to pack all of the globals into a
* structure and allocate a per-thread instance of that structure here.
*
* NOTE: This applies only in the FLAT and PROTECTED build modes. In the
* KERNEL build mode, this will be a separate process with its own private
* global variables.
*/
ret = sem_wait(&g_exclsem);
if (ret < 0)
{
fprintf(stderr, "sem_wait failed: %d\n", errno);
exit(1);
}
#endif
/* Set defaults. */
g_mode = COMPRESS;
g_verbose = false;
g_force = 0;
blocksize = BLOCKSIZE;
g_mode = COMPRESS;
g_verbose = false;
g_force = 0;
g_blocksize = BLOCKSIZE;
#ifndef CONFIG_DISABLE_ENVIRON
/* Block size may be specified as an environment variable */
@ -446,10 +479,10 @@ int lzf_main(int argc, FAR char *argv[])
p = getenv("LZF_BLOCKSIZE");
if (p)
{
blocksize = strtoul(p, 0, 0);
if (!blocksize || blocksize > MAX_BLOCKSIZE)
g_blocksize = strtoul(p, 0, 0);
if (g_blocksize == 0 || g_blocksize > MAX_BLOCKSIZE)
{
blocksize = BLOCKSIZE;
g_blocksize = BLOCKSIZE;
}
}
#endif
@ -486,10 +519,10 @@ int lzf_main(int argc, FAR char *argv[])
break;
case 'b':
blocksize = strtoul(optarg, 0, 0);
if (!blocksize || blocksize > MAX_BLOCKSIZE)
g_blocksize = strtoul(optarg, 0, 0);
if (g_blocksize == 0 || g_blocksize > MAX_BLOCKSIZE)
{
blocksize = BLOCKSIZE;
g_blocksize = BLOCKSIZE;
}
break;
@ -511,14 +544,14 @@ int lzf_main(int argc, FAR char *argv[])
{
fprintf(stderr, "%s: compressed data not read from a terminal. "
"Use -f to force decompression.\n", g_imagename);
exit(1);
lzf_exit(1);
}
if (g_mode == COMPRESS && isatty(1))
{
fprintf(stderr, "%s: compressed data not written to a terminal. "
"Use -f to force compression.\n", g_imagename);
exit(1);
lzf_exit(1);
}
}
#endif
@ -532,7 +565,7 @@ int lzf_main(int argc, FAR char *argv[])
ret = uncompress_fd(0, 1);
}
exit(ret ? 1 : 0);
lzf_exit(ret ? 1 : 0);
}
while (optind < argc)
@ -540,5 +573,5 @@ int lzf_main(int argc, FAR char *argv[])
ret |= run_file(argv[optind++]);
}
exit(ret ? 1 : 0);
lzf_exit(ret ? 1 : 0);
}