@@ -45,7 +45,8 @@ JsVar jsVars[JSVAR_CACHE_SIZE];
45
45
unsigned int jsVarsSize = JSVAR_CACHE_SIZE ;
46
46
#endif
47
47
48
- JsVarRef jsVarFirstEmpty ; ///< reference of first unused variable (variables are in a linked list)
48
+ volatile JsVarRef jsVarFirstEmpty ; ///< reference of first unused variable (variables are in a linked list)
49
+ volatile bool isMemoryBusy ; ///< Are we doing garbage collection or similar, so can't access memory?
49
50
50
51
// ----------------------------------------------------------------------------
51
52
// ----------------------------------------------------------------------------
@@ -161,6 +162,8 @@ void jsvSetMaxVarsUsed(unsigned int size) {
161
162
162
163
// maps the empty variables in...
163
164
void jsvCreateEmptyVarList () {
165
+ assert (!isMemoryBusy );
166
+ isMemoryBusy = true;
164
167
jsVarFirstEmpty = 0 ;
165
168
JsVar firstVar ; // temporary var to simplify code in the loop below
166
169
jsvSetNextSibling (& firstVar , 0 );
@@ -179,12 +182,15 @@ void jsvCreateEmptyVarList() {
179
182
}
180
183
jsvSetNextSibling (lastEmpty , 0 );
181
184
jsVarFirstEmpty = jsvGetNextSibling (& firstVar );
185
+ isMemoryBusy = false;
182
186
}
183
187
184
188
/* Removes the empty variable counter, cleaving clear runs of 0s
185
189
where no data resides. This helps if compressing the variables
186
190
for storage. */
187
191
void jsvClearEmptyVarList () {
192
+ assert (!isMemoryBusy );
193
+ isMemoryBusy = true;
188
194
jsVarFirstEmpty = 0 ;
189
195
JsVarRef i ;
190
196
for (i = 1 ;i <=jsVarsSize ;i ++ ) {
@@ -197,6 +203,7 @@ void jsvClearEmptyVarList() {
197
203
i = (JsVarRef )(i + jsvGetFlatStringBlocks (var ));
198
204
}
199
205
}
206
+ isMemoryBusy = false;
200
207
}
201
208
202
209
void jsvSoftInit () {
@@ -281,6 +288,8 @@ unsigned int jsvGetMemoryTotal() {
281
288
/// Try and allocate more memory - only works if RESIZABLE_JSVARS is defined
282
289
void jsvSetMemoryTotal (unsigned int jsNewVarCount ) {
283
290
#ifdef RESIZABLE_JSVARS
291
+ assert (!isMemoryBusy );
292
+ isMemoryBusy = true;
284
293
if (jsNewVarCount <= jsVarsSize ) return ; // never allow us to have less!
285
294
// When resizing, we just allocate a bunch more
286
295
unsigned int oldSize = jsVarsSize ;
@@ -298,6 +307,7 @@ void jsvSetMemoryTotal(unsigned int jsNewVarCount) {
298
307
assert (!jsVarFirstEmpty );
299
308
jsVarFirstEmpty = jsvInitJsVars (oldSize + 1 , jsVarsSize - oldSize );
300
309
// jsiConsolePrintf("Resized memory from %d blocks to %d\n", oldBlockCount, newBlockCount);
310
+ isMemoryBusy = false;
301
311
#else
302
312
NOT_USED (jsNewVarCount );
303
313
assert (0 );
@@ -367,24 +377,40 @@ void jsvResetVariable(JsVar *v, JsVarFlags flags) {
367
377
}
368
378
369
379
JsVar * jsvNewWithFlags (JsVarFlags flags ) {
380
+ if (isMemoryBusy ) {
381
+ jsErrorFlags |= JSERR_MEMORY_BUSY ;
382
+ return 0 ;
383
+ }
370
384
if (jsVarFirstEmpty != 0 ) {
371
- assert (jsvGetAddressOf (jsVarFirstEmpty )-> flags == JSV_UNUSED );
372
385
jshInterruptOff (); // to allow this to be used from an IRQ
373
386
JsVar * v = jsvGetAddressOf (jsVarFirstEmpty ); // jsvResetVariable will lock
374
- jsVarFirstEmpty = jsvGetNextSibling (v ); // move our reference to the next in the free list
387
+ jsVarFirstEmpty = jsvGetNextSibling (v ); // move our reference to the next in the fr
375
388
jshInterruptOn ();
389
+ assert (v -> flags == JSV_UNUSED );
390
+ // Cope with IRQs/multi-threading when getting a new free variable
391
+ /* JsVarRef empty;
392
+ JsVarRef next;
393
+ JsVar *v;
394
+ do {
395
+ empty = jsVarFirstEmpty;
396
+ v = jsvGetAddressOf(empty); // jsvResetVariable will lock
397
+ next = jsvGetNextSibling(v); // move our reference to the next in the free list
398
+ } while (!__sync_bool_compare_and_swap(&jsVarFirstEmpty, empty, next));
399
+ assert(v->flags == JSV_UNUSED);*/
376
400
jsvResetVariable (v , flags ); // setup variable, and add one lock
377
401
// return pointer
378
402
return v ;
379
403
}
380
404
jsErrorFlags |= JSERR_LOW_MEMORY ;
381
405
/* we don't have memory - second last hope - run garbage collector */
382
- if (jsvGarbageCollect ())
406
+ if (jsvGarbageCollect ()) {
383
407
return jsvNewWithFlags (flags ); // if it freed something, continue
408
+ }
384
409
/* we don't have memory - last hope - ask jsInteractive to try and free some it
385
410
may have kicking around */
386
- if (jsiFreeMoreMemory ())
411
+ if (jsiFreeMoreMemory ()) {
387
412
return jsvNewWithFlags (flags );
413
+ }
388
414
/* We couldn't claim any more memory by Garbage collecting... */
389
415
#ifdef RESIZABLE_JSVARS
390
416
jsvSetMemoryTotal (jsVarsSize * 2 );
@@ -628,6 +654,11 @@ JsVarRef jsvUnRefRef(JsVarRef ref) {
628
654
}
629
655
630
656
JsVar * jsvNewFlatStringOfLength (unsigned int byteLength ) {
657
+ if (isMemoryBusy ) {
658
+ jsErrorFlags |= JSERR_MEMORY_BUSY ;
659
+ return 0 ;
660
+ }
661
+ isMemoryBusy = true;
631
662
// Work out how many blocks we need. One for the header, plus some for the characters
632
663
size_t blocks = 1 + ((byteLength + sizeof (JsVar )- 1 ) / sizeof (JsVar ));
633
664
// Now try and find them
@@ -695,18 +726,15 @@ JsVar *jsvNewFlatStringOfLength(unsigned int byteLength) {
695
726
}
696
727
jsvSetNextSibling (lastEmpty , 0 );
697
728
jsVarFirstEmpty = jsvGetNextSibling (& firstVar );
698
-
729
+ isMemoryBusy = false;
699
730
// Return whatever we had (0 if we couldn't manage it)
700
731
return flatString ;
701
732
}
702
733
703
734
JsVar * jsvNewFromString (const char * str ) {
704
735
// Create a var
705
736
JsVar * first = jsvNewWithFlags (JSV_STRING_0 );
706
- if (!first ) {
707
- jsWarn ("Unable to create string as not enough memory" );
708
- return 0 ;
709
- }
737
+ if (!first ) return 0 ; // out of memory
710
738
// Now we copy the string, but keep creating new jsVars if we go
711
739
// over the end
712
740
JsVar * var = jsvLockAgain (first );
@@ -725,7 +753,7 @@ JsVar *jsvNewFromString(const char *str) {
725
753
if (* str ) {
726
754
JsVar * next = jsvNewWithFlags (JSV_STRING_EXT_0 );
727
755
if (!next ) {
728
- jsWarn ( " Truncating string as not enough memory" );
756
+ // Truncating string as not enough memory
729
757
jsvUnLock (var );
730
758
return first ;
731
759
}
@@ -3123,6 +3151,8 @@ static void jsvGarbageCollectMarkUsed(JsVar *var) {
3123
3151
3124
3152
/** Run a garbage collection sweep - return true if things have been freed */
3125
3153
bool jsvGarbageCollect () {
3154
+ if (isMemoryBusy ) return false;
3155
+ isMemoryBusy = true;
3126
3156
JsVarRef i ;
3127
3157
// clear garbage collect flags
3128
3158
for (i = 1 ;i <=jsVarsSize ;i ++ ) {
@@ -3224,7 +3254,7 @@ bool jsvGarbageCollect() {
3224
3254
* our fake 'firstVar' variable */
3225
3255
jsvSetNextSibling (lastEmpty , 0 );
3226
3256
jsVarFirstEmpty = jsvGetNextSibling (& firstVar );
3227
-
3257
+ isMemoryBusy = false;
3228
3258
return freedSomething ;
3229
3259
}
3230
3260
0 commit comments