Skip to content

Commit 109c1de

Browse files
committed
py: Make gc.enable/disable just control auto-GC; alloc is still allowed.
gc.enable/disable are now the same as CPython: they just control whether automatic garbage collection is enabled or not. If disabled, you can still allocate heap memory, and initiate a manual collection.
1 parent 4029f51 commit 109c1de

10 files changed

Lines changed: 39 additions & 16 deletions

File tree

docs/library/gc.rst

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,21 @@
44
.. module:: gc
55
:synopsis: control the garbage collector
66

7-
8-
97
Functions
108
---------
119

12-
.. function:: collect()
10+
.. function:: enable()
1311

14-
Run a garbage collection.
12+
Enable automatic garbage collection.
1513

1614
.. function:: disable()
1715

18-
Disable the garbage collector.
16+
Disable automatic garbage collection. Heap memory can still be allocated,
17+
and garbage collection can still be initiated manually using :meth:`gc.collect`.
1918

20-
.. function:: enable()
19+
.. function:: collect()
2120

22-
Enable the garbage collector.
21+
Run a garbage collection.
2322

2423
.. function:: mem_alloc()
2524

py/gc.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <stdio.h>
2929
#include <string.h>
3030
#include <stdbool.h>
31+
#include <stdint.h>
3132

3233
#include "mpconfig.h"
3334
#include "misc.h"
@@ -68,7 +69,8 @@ STATIC mp_uint_t *gc_pool_end;
6869
STATIC int gc_stack_overflow;
6970
STATIC mp_uint_t gc_stack[STACK_SIZE];
7071
STATIC mp_uint_t *gc_sp;
71-
STATIC mp_uint_t gc_lock_depth;
72+
STATIC uint16_t gc_lock_depth;
73+
uint16_t gc_auto_collect_enabled;
7274
STATIC mp_uint_t gc_last_free_atb_index;
7375

7476
// ATB = allocation table byte
@@ -163,6 +165,9 @@ void gc_init(void *start, void *end) {
163165
// unlock the GC
164166
gc_lock_depth = 0;
165167

168+
// allow auto collection
169+
gc_auto_collect_enabled = 1;
170+
166171
DEBUG_printf("GC layout:\n");
167172
DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_alloc_table_start, gc_alloc_table_byte_len, gc_alloc_table_byte_len * BLOCKS_PER_ATB);
168173
#if MICROPY_ENABLE_FINALISER
@@ -375,7 +380,7 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
375380
mp_uint_t end_block;
376381
mp_uint_t start_block;
377382
mp_uint_t n_free = 0;
378-
int collected = 0;
383+
int collected = !gc_auto_collect_enabled;
379384
for (;;) {
380385

381386
// look for a run of n_blocks available blocks

py/gc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ void gc_lock(void);
3232
void gc_unlock(void);
3333
bool gc_is_locked(void);
3434

35+
// This variable controls auto garbage collection. If set to 0 then the
36+
// GC won't automatically run when gc_alloc can't find enough blocks. But
37+
// you can still allocate/free memory and also explicitly call gc_collect.
38+
extern uint16_t gc_auto_collect_enabled;
39+
3540
// A given port must implement gc_collect by using the other collect functions.
3641
void gc_collect(void);
3742
void gc_collect_start(void);

py/malloc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <stdio.h>
2828
#include <stdlib.h>
2929
#include <string.h>
30+
#include <stdint.h>
3031

3132
#include "mpconfig.h"
3233
#include "misc.h"

py/modgc.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,13 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include <stdint.h>
28+
2729
#include "mpconfig.h"
2830
#include "misc.h"
2931
#include "qstr.h"
3032
#include "obj.h"
31-
#include "builtin.h"
3233
#include "runtime.h"
33-
#include "objlist.h"
34-
#include "objtuple.h"
35-
#include "objstr.h"
3634
#include "gc.h"
3735

3836
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
@@ -56,19 +54,24 @@ MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
5654
/// \function disable()
5755
/// Disable the garbage collector.
5856
STATIC mp_obj_t gc_disable(void) {
59-
gc_lock();
57+
gc_auto_collect_enabled = 0;
6058
return mp_const_none;
6159
}
6260
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
6361

6462
/// \function enable()
6563
/// Enable the garbage collector.
6664
STATIC mp_obj_t gc_enable(void) {
67-
gc_unlock();
65+
gc_auto_collect_enabled = 1;
6866
return mp_const_none;
6967
}
7068
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
7169

70+
STATIC mp_obj_t gc_isenabled(void) {
71+
return MP_BOOL(gc_auto_collect_enabled);
72+
}
73+
MP_DEFINE_CONST_FUN_OBJ_0(gc_isenabled_obj, gc_isenabled);
74+
7275
/// \function mem_free()
7376
/// Return the number of bytes of available heap RAM.
7477
STATIC mp_obj_t gc_mem_free(void) {
@@ -92,6 +95,7 @@ STATIC const mp_map_elem_t mp_module_gc_globals_table[] = {
9295
{ MP_OBJ_NEW_QSTR(MP_QSTR_collect), (mp_obj_t)&gc_collect_obj },
9396
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&gc_disable_obj },
9497
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&gc_enable_obj },
98+
{ MP_OBJ_NEW_QSTR(MP_QSTR_isenabled), (mp_obj_t)&gc_isenabled_obj },
9599
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_free), (mp_obj_t)&gc_mem_free_obj },
96100
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_alloc), (mp_obj_t)&gc_mem_alloc_obj },
97101
};

py/objexcept.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <stdarg.h>
2929
#include <assert.h>
3030
#include <stdio.h>
31+
#include <stdint.h>
3132

3233
#include "mpconfig.h"
3334
#include "nlr.h"

py/qstr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include <assert.h>
2828
#include <string.h>
29+
#include <stdint.h>
2930

3031
#include "mpconfig.h"
3132
#include "misc.h"

py/qstrdefs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ Q(gc)
470470
Q(collect)
471471
Q(disable)
472472
Q(enable)
473+
Q(isenabled)
473474
Q(mem_free)
474475
Q(mem_alloc)
475476
#endif

tests/micropython/heapalloc.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ def h():
2020
g(i) # default arg (second one)
2121
g(i, i) # 2 args
2222

23-
# call h with heap allocation disabled
23+
# call h with heap allocation disabled and all memory used up
2424
gc.disable()
25+
try:
26+
while True:
27+
'a'.lower # allocates 1 cell for boundmeth
28+
except MemoryError:
29+
pass
2530
h()
2631
gc.enable()

unix/gccollect.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
#include <stdio.h>
28+
#include <stdint.h>
2829

2930
#include "mpconfig.h"
3031
#include "misc.h"

0 commit comments

Comments
 (0)