Browse files

Make Sereal::Encoder re-entrant

Should only be necessary in bizarre edge cases, but, well, ...
  • Loading branch information...
1 parent 5a940f1 commit 49032214a6c987f026d08175f1dab8657b8707c9 @tsee tsee committed Oct 25, 2012
Showing with 64 additions and 9 deletions.
  1. +52 −8 Perl/Encoder/srl_encoder.c
  2. +12 −1 Perl/Encoder/srl_encoder.h
View
60 Perl/Encoder/srl_encoder.c
@@ -158,7 +158,7 @@ srl_destructor_hook(pTHX_ void *p)
void
srl_clear_encoder(pTHX_ srl_encoder_t *enc)
{
- if (enc->pos == enc->buf_start) {
+ if (!SRL_ENC_HAVE_OPER_FLAG(enc, SRL_OF_ENCODER_DIRTY)) {
warn("Sereal Encoder being cleared but in virgin state. That is unexpected.");
}
@@ -170,6 +170,8 @@ srl_clear_encoder(pTHX_ srl_encoder_t *enc)
if (enc->weak_seenhash != NULL)
PTABLE_clear(enc->weak_seenhash);
enc->pos = enc->buf_start;
+
+ SRL_ENC_RESET_OPER_FLAG(enc, SRL_OF_ENCODER_DIRTY);
}
void
@@ -186,28 +188,45 @@ srl_destroy_encoder(pTHX_ srl_encoder_t *enc)
Safefree(enc);
}
-/* Builds the C-level configuration and state struct.
- * Automatically freed at scope boundary. */
-srl_encoder_t *
-srl_build_encoder_struct(pTHX_ HV *opt)
+/* allocate an empty encoder struct - flags still to be set up */
+static SRL_INLINE srl_encoder_t *
+srl_empty_encoder_struct(pTHX)
{
srl_encoder_t *enc;
- SV **svp;
-
Newx(enc, 1, srl_encoder_t);
+ if (enc == NULL)
+ croak("Out of memory");
/* Init struct */
Newx(enc->buf_start, INITIALIZATION_SIZE, char);
+ if (enc->buf_start == NULL) {
+ Safefree(enc);
+ croak("Out of memory");
+ }
enc->buf_end = enc->buf_start + INITIALIZATION_SIZE - 1;
enc->pos = enc->buf_start;
enc->depth = 0;
- enc->flags = 0;
+ enc->operational_flags = 0;
+ /*enc->flags = 0;*/ /* to be set elsewhere */
enc->weak_seenhash = NULL;
enc->str_seenhash = NULL;
enc->ref_seenhash = NULL;
enc->snappy_workmem = NULL;
+ return enc;
+}
+
+/* Builds the C-level configuration and state struct. */
+srl_encoder_t *
+srl_build_encoder_struct(pTHX_ HV *opt)
+{
+ srl_encoder_t *enc;
+ SV **svp;
+
+ enc = srl_empty_encoder_struct(aTHX);
+ enc->flags = 0;
+
/* load options */
if (opt != NULL) {
int undef_unknown = 0;
@@ -256,6 +275,18 @@ srl_build_encoder_struct(pTHX_ HV *opt)
/* SRL_F_SHARED_HASHKEYS on by default */
enc->flags |= SRL_F_SHARED_HASHKEYS;
}
+
+ DEBUG_ASSERT_BUF_SANE(enc);
+ return enc;
+}
+
+/* clone an encoder without current state */
+srl_encoder_t *
+srl_build_encoder_struct_alike(pTHX_ srl_encoder_t *proto)
+{
+ srl_encoder_t *enc;
+ enc = srl_empty_encoder_struct(aTHX);
+ enc->flags = proto->flags;
DEBUG_ASSERT_BUF_SANE(enc);
return enc;
}
@@ -409,6 +440,15 @@ srl_dump_data_structure(pTHX_ srl_encoder_t *enc, SV *src)
{
if (DEBUGHACK) warn("== start dump");
+ /* Check whether encoder is in use and create a new one on the
+ * fly if necessary. Should only happen in bizarre edge cases... hopefully. */
+ if (SRL_ENC_HAVE_OPER_FLAG(enc, SRL_OF_ENCODER_DIRTY)) {
+ srl_encoder_t * const proto = enc;
+ enc = srl_build_encoder_struct_alike(aTHX_ proto);
+ }
+ /* Set to being in use */;
+ SRL_ENC_SET_OPER_FLAG(enc, SRL_OF_ENCODER_DIRTY);
+
/* Register our structure for destruction on scope exit */
SAVEDESTRUCTOR_X(&srl_destructor_hook, (void *)enc);
@@ -496,6 +536,10 @@ srl_dump_data_structure(pTHX_ srl_encoder_t *enc, SV *src)
#endif
}
}
+
+ /* NOT doing a
+ * SRL_ENC_RESET_OPER_FLAG(enc, SRL_OF_ENCODER_DIRTY);
+ * here because we're relying on the SAVEDESTRUCTOR_X call. */
if (DEBUGHACK) warn("== end dump");
}
View
13 Perl/Encoder/srl_encoder.h
@@ -17,6 +17,7 @@ typedef struct {
char *buf_end; /* ptr to end of output buffer */
char *pos; /* ptr to current position within output buffer */
+ U32 operational_flags; /* flags that pertain to one encode run (rather than being options): See SRL_OF_* defines */
U32 flags; /* flag-like options: See SRL_F_* defines */
unsigned int depth; /* current Perl-ref recursion depth */
ptable_ptr ref_seenhash; /* ptr table for avoiding circular refs */
@@ -27,8 +28,10 @@ typedef struct {
IV snappy_threshold; /* do not compress things smaller than this even if Snappy enabled */
} srl_encoder_t;
-/* constructor; don't need destructor, this sets up a callback */
+/* constructor from options */
srl_encoder_t *srl_build_encoder_struct(pTHX_ HV *opt);
+/* clone; "constructor from prototype" */
+srl_encoder_t *srl_build_encoder_struct_alike(pTHX_ srl_encoder_t *proto);
void srl_clear_encoder(pTHX_ srl_encoder_t *enc);
@@ -40,6 +43,7 @@ void srl_write_header(pTHX_ srl_encoder_t *enc);
/* Start dumping a top-level SV */
void srl_dump_data_structure(pTHX_ srl_encoder_t *enc, SV *src);
+
/* define option bits in srl_encoder_t's flags member */
/* Will default to "on". If set, hash keys will be shared using COPY.
@@ -70,6 +74,13 @@ void srl_dump_data_structure(pTHX_ srl_encoder_t *enc, SV *src);
* if the unsupported item has string overloading. */
#define SRL_F_NOWARN_UNKNOWN_OVERLOAD 128UL
+/* Set while the encoder is in active use / dirty */
+#define SRL_OF_ENCODER_DIRTY 1UL
+
#define SRL_ENC_HAVE_OPTION(enc, flag_num) ((enc)->flags & flag_num)
+#define SRL_ENC_HAVE_OPER_FLAG(enc, flag_num) ((enc)->operational_flags & (flag_num))
+#define SRL_ENC_SET_OPER_FLAG(enc, flag_num) STMT_START {(enc)->operational_flags |= (flag_num);}STMT_END
+#define SRL_ENC_RESET_OPER_FLAG(enc, flag_num) STMT_START {(enc)->operational_flags &= ~(flag_num);}STMT_END
+
#endif

0 comments on commit 4903221

Please sign in to comment.