[PATCH 9/9] lzma: make lzma reentrant

From: Phillip Lougher
Date: Mon Dec 07 2009 - 03:39:12 EST



The error function pointer used by lzma is global (file scope) which
prevents it being used concurrently. This patch removes the global
error pointer use, and instead passes it to all functions that need it.

The error function pointer is still used by bzip2 and inflate.
This patch moves the definition into the separate bzip2/inflate
header files. This prevents gcc from complaining about an
unused definition compiling lzma.

Signed-off-by: Phillip Lougher <phillip@xxxxxxxxxxxxxxxxxxx>
---
include/linux/decompress/bunzip2_mm.h | 1 +
include/linux/decompress/inflate_mm.h | 1 +
include/linux/decompress/mm.h | 1 -
lib/decompress_unlzma.c | 82 +++++++++++++++++----------------
4 files changed, 44 insertions(+), 41 deletions(-)

diff --git a/include/linux/decompress/bunzip2_mm.h b/include/linux/decompress/bunzip2_mm.h
index cac6fef..863efd0 100644
--- a/include/linux/decompress/bunzip2_mm.h
+++ b/include/linux/decompress/bunzip2_mm.h
@@ -7,6 +7,7 @@
#else
/* Compile for initramfs/initrd code only */
#define INIT __init
+static void(*error)(char *m);
#endif

#endif
diff --git a/include/linux/decompress/inflate_mm.h b/include/linux/decompress/inflate_mm.h
index ca4a2ae..87a742b 100644
--- a/include/linux/decompress/inflate_mm.h
+++ b/include/linux/decompress/inflate_mm.h
@@ -7,6 +7,7 @@
#else
/* Compile for initramfs/initrd code only */
#define INIT __init
+static void(*error)(char *m);
#endif

#endif
diff --git a/include/linux/decompress/mm.h b/include/linux/decompress/mm.h
index 80f5ba4..32651e4 100644
--- a/include/linux/decompress/mm.h
+++ b/include/linux/decompress/mm.h
@@ -72,7 +72,6 @@ static void free(void *where)
#define large_malloc(a) vmalloc(a)
#define large_free(a) vfree(a)

-static void(*error)(char *m);
#define set_error_fn(x) error = x;

#define STATIC
diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c
index a614b26..3e85763 100644
--- a/lib/decompress_unlzma.c
+++ b/lib/decompress_unlzma.c
@@ -89,7 +89,7 @@ static int nofill(void *buffer, unsigned int len)
}

/* Called twice: once at startup and once in rc_normalize() */
-static void INIT rc_read(struct rc *rc)
+static void INIT rc_read(struct rc *rc, void(*error)(char *x))
{
rc->buffer_size = rc->fill((char *)rc->buffer, LZMA_IOBUF_SIZE);
if (rc->buffer_size <= 0)
@@ -116,13 +116,13 @@ static inline void INIT rc_init(struct rc *rc,
rc->range = 0xFFFFFFFF;
}

-static inline void INIT rc_init_code(struct rc *rc)
+static inline void INIT rc_init_code(struct rc *rc, void(*error)(char *x))
{
int i;

for (i = 0; i < 5; i++) {
if (rc->ptr >= rc->buffer_end)
- rc_read(rc);
+ rc_read(rc, error);
rc->code = (rc->code << 8) | *rc->ptr++;
}
}
@@ -135,32 +135,33 @@ static inline void INIT rc_free(struct rc *rc)
}

/* Called twice, but one callsite is in inline'd rc_is_bit_0_helper() */
-static void INIT rc_do_normalize(struct rc *rc)
+static void INIT rc_do_normalize(struct rc *rc, void(*error)(char *x))
{
if (rc->ptr >= rc->buffer_end)
- rc_read(rc);
+ rc_read(rc, error);
rc->range <<= 8;
rc->code = (rc->code << 8) | *rc->ptr++;
}
-static inline void INIT rc_normalize(struct rc *rc)
+static inline void INIT rc_normalize(struct rc *rc, void(*error)(char *x))
{
if (rc->range < (1 << RC_TOP_BITS))
- rc_do_normalize(rc);
+ rc_do_normalize(rc, error);
}

/* Called 9 times */
/* Why rc_is_bit_0_helper exists?
*Because we want to always expose (rc->code < rc->bound) to optimizer
*/
-static inline uint32_t INIT rc_is_bit_0_helper(struct rc *rc, uint16_t *p)
+static inline uint32_t INIT rc_is_bit_0_helper(struct rc *rc, uint16_t *p,
+ void (*error)(char *x))
{
- rc_normalize(rc);
+ rc_normalize(rc, error);
rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
return rc->bound;
}
-static inline int INIT rc_is_bit_0(struct rc *rc, uint16_t *p)
+static inline int INIT rc_is_bit_0(struct rc *rc, uint16_t *p, void(*error)(char *x))
{
- uint32_t t = rc_is_bit_0_helper(rc, p);
+ uint32_t t = rc_is_bit_0_helper(rc, p, error);
return rc->code < t;
}

@@ -178,9 +179,9 @@ static inline void rc_update_bit_1(struct rc *rc, uint16_t *p)
}

/* Called 4 times in unlzma loop */
-static int INIT rc_get_bit(struct rc *rc, uint16_t *p, int *symbol)
+static int INIT rc_get_bit(struct rc *rc, uint16_t *p, int *symbol, void(*error)(char *x))
{
- if (rc_is_bit_0(rc, p)) {
+ if (rc_is_bit_0(rc, p, error)) {
rc_update_bit_0(rc, p);
*symbol *= 2;
return 0;
@@ -192,9 +193,9 @@ static int INIT rc_get_bit(struct rc *rc, uint16_t *p, int *symbol)
}

/* Called once */
-static inline int INIT rc_direct_bit(struct rc *rc)
+static inline int INIT rc_direct_bit(struct rc *rc , void(*error)(char *x))
{
- rc_normalize(rc);
+ rc_normalize(rc, error);
rc->range >>= 1;
if (rc->code >= rc->range) {
rc->code -= rc->range;
@@ -205,13 +206,14 @@ static inline int INIT rc_direct_bit(struct rc *rc)

/* Called twice */
static inline void INIT
-rc_bit_tree_decode(struct rc *rc, uint16_t *p, int num_levels, int *symbol)
+rc_bit_tree_decode(struct rc *rc, uint16_t *p, int num_levels, int *symbol,
+ void(*error)(char *x))
{
int i = num_levels;

*symbol = 1;
while (i--)
- rc_get_bit(rc, p + *symbol, symbol);
+ rc_get_bit(rc, p + *symbol, symbol, error);
*symbol -= 1 << num_levels;
}

@@ -348,7 +350,8 @@ static inline void INIT copy_bytes(struct writer *wr,
static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
struct cstate *cst, uint16_t *p,
int pos_state, uint16_t *prob,
- int lc, uint32_t literal_pos_mask) {
+ int lc, uint32_t literal_pos_mask,
+ void(*error)(char *x)) {
int mi = 1;
rc_update_bit_0(rc, prob);
prob = (p + LZMA_LITERAL +
@@ -366,7 +369,7 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
match_byte <<= 1;
bit = match_byte & 0x100;
prob_lit = prob + 0x100 + bit + mi;
- if (rc_get_bit(rc, prob_lit, &mi)) {
+ if (rc_get_bit(rc, prob_lit, &mi, error)) {
if (!bit)
break;
} else {
@@ -377,7 +380,7 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
}
while (mi < 0x100) {
uint16_t *prob_lit = prob + mi;
- rc_get_bit(rc, prob_lit, &mi);
+ rc_get_bit(rc, prob_lit, &mi, error);
}
write_byte(wr, mi);
if (cst->state < 4)
@@ -390,7 +393,8 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc,

static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
struct cstate *cst, uint16_t *p,
- int pos_state, uint16_t *prob) {
+ int pos_state, uint16_t *prob,
+ void(*error)(char *x)) {
int offset;
uint16_t *prob_len;
int num_bits;
@@ -398,7 +402,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,

rc_update_bit_1(rc, prob);
prob = p + LZMA_IS_REP + cst->state;
- if (rc_is_bit_0(rc, prob)) {
+ if (rc_is_bit_0(rc, prob, error)) {
rc_update_bit_0(rc, prob);
cst->rep3 = cst->rep2;
cst->rep2 = cst->rep1;
@@ -408,13 +412,13 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
} else {
rc_update_bit_1(rc, prob);
prob = p + LZMA_IS_REP_G0 + cst->state;
- if (rc_is_bit_0(rc, prob)) {
+ if (rc_is_bit_0(rc, prob, error)) {
rc_update_bit_0(rc, prob);
prob = (p + LZMA_IS_REP_0_LONG
+ (cst->state <<
LZMA_NUM_POS_BITS_MAX) +
pos_state);
- if (rc_is_bit_0(rc, prob)) {
+ if (rc_is_bit_0(rc, prob, error)) {
rc_update_bit_0(rc, prob);

cst->state = cst->state < LZMA_NUM_LIT_STATES ?
@@ -429,13 +433,13 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,

rc_update_bit_1(rc, prob);
prob = p + LZMA_IS_REP_G1 + cst->state;
- if (rc_is_bit_0(rc, prob)) {
+ if (rc_is_bit_0(rc, prob, error)) {
rc_update_bit_0(rc, prob);
distance = cst->rep1;
} else {
rc_update_bit_1(rc, prob);
prob = p + LZMA_IS_REP_G2 + cst->state;
- if (rc_is_bit_0(rc, prob)) {
+ if (rc_is_bit_0(rc, prob, error)) {
rc_update_bit_0(rc, prob);
distance = cst->rep2;
} else {
@@ -453,7 +457,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
}

prob_len = prob + LZMA_LEN_CHOICE;
- if (rc_is_bit_0(rc, prob_len)) {
+ if (rc_is_bit_0(rc, prob_len, error)) {
rc_update_bit_0(rc, prob_len);
prob_len = (prob + LZMA_LEN_LOW
+ (pos_state <<
@@ -463,7 +467,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
} else {
rc_update_bit_1(rc, prob_len);
prob_len = prob + LZMA_LEN_CHOICE_2;
- if (rc_is_bit_0(rc, prob_len)) {
+ if (rc_is_bit_0(rc, prob_len, error)) {
rc_update_bit_0(rc, prob_len);
prob_len = (prob + LZMA_LEN_MID
+ (pos_state <<
@@ -479,7 +483,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
}
}

- rc_bit_tree_decode(rc, prob_len, num_bits, &len);
+ rc_bit_tree_decode(rc, prob_len, num_bits, &len, error);
len += offset;

if (cst->state < 4) {
@@ -494,7 +498,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
<< LZMA_NUM_POS_SLOT_BITS);
rc_bit_tree_decode(rc, prob,
LZMA_NUM_POS_SLOT_BITS,
- &pos_slot);
+ &pos_slot, error);
if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
int i, mi;
num_bits = (pos_slot >> 1) - 1;
@@ -507,7 +511,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
num_bits -= LZMA_NUM_ALIGN_BITS;
while (num_bits--)
cst->rep0 = (cst->rep0 << 1) |
- rc_direct_bit(rc);
+ rc_direct_bit(rc, error);
prob = p + LZMA_ALIGN;
cst->rep0 <<= LZMA_NUM_ALIGN_BITS;
num_bits = LZMA_NUM_ALIGN_BITS;
@@ -515,7 +519,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
i = 1;
mi = 1;
while (num_bits--) {
- if (rc_get_bit(rc, prob + mi, &mi))
+ if (rc_get_bit(rc, prob + mi, &mi, error))
cst->rep0 |= i;
i <<= 1;
}
@@ -537,7 +541,7 @@ STATIC int INIT unlzma(unsigned char *buf, int in_len,
int(*flush)(void*, unsigned int),
unsigned char *output,
int *posp,
- void(*error_fn)(char *x)
+ void(*error)(char *x)
)
{
struct lzma_header header;
@@ -553,8 +557,6 @@ STATIC int INIT unlzma(unsigned char *buf, int in_len,
unsigned char *inbuf;
int ret = -1;

- set_error_fn(error_fn);
-
if (buf)
inbuf = buf;
else
@@ -577,7 +579,7 @@ STATIC int INIT unlzma(unsigned char *buf, int in_len,

for (i = 0; i < sizeof(header); i++) {
if (rc.ptr >= rc.buffer_end)
- rc_read(&rc);
+ rc_read(&rc, error);
((unsigned char *)&header)[i] = *rc.ptr++;
}

@@ -622,17 +624,17 @@ STATIC int INIT unlzma(unsigned char *buf, int in_len,
for (i = 0; i < num_probs; i++)
p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;

- rc_init_code(&rc);
+ rc_init_code(&rc, error);

while (get_pos(&wr) < header.dst_size) {
int pos_state = get_pos(&wr) & pos_state_mask;
uint16_t *prob = p + LZMA_IS_MATCH +
(cst.state << LZMA_NUM_POS_BITS_MAX) + pos_state;
- if (rc_is_bit_0(&rc, prob))
+ if (rc_is_bit_0(&rc, prob, error))
process_bit0(&wr, &rc, &cst, p, pos_state, prob,
- lc, literal_pos_mask);
+ lc, literal_pos_mask, error);
else {
- process_bit1(&wr, &rc, &cst, p, pos_state, prob);
+ process_bit1(&wr, &rc, &cst, p, pos_state, prob, error);
if (cst.rep0 == 0)
break;
}
--
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/