mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Fix exceptions from freeing fb_alloc_mark
This fix creates a flag that prevents fb_alloc_free_till_mark() from doing anything unless there was a previous fb_alloc_mark(). Once fb_alloc_free_till_mark() is called it will no longer do anything until there's another fb_alloc_mark(). This means that if an exception is triggered while in code that previously did fb_alloc_mark() the stack will be cleaned up. If the fb_alloc_mark() method is not called then the stack will not be cleaned up and that memory fb_alloc()'ed will remain until a soft reset. All OpenMV Cam library code is designed to fb_alloc_mark() before using the fb stack and then fb_alloc_free_till_mark() when complete. However, in the case of py_sensor_alloc_extra_fb() it doesn't mark first such that the RAM it allocates stays across exceptions and is only free'd via py_sensor_dealloc_extra_fb() or via a soft reset. ... Summary of changes: fb_alloc.c -> Added a semaphore lock to prevent fb_alloc_free_till_mark() from doing anything unless fb_alloc_mark() was called first. py_sensor.c -> Removed calling fb_alloc_mark() and fb_alloc_free_till_mark() and re-arranged code calls to prevent a trival leak sitatuion on heap exhaustion. py_image.c, py_fir.c, py_lcd.c py_tv.c -> Added fb_alloc_mark() and fb_alloc_free_till_mark() to methods originally coded without using it. ... Note - I coded the mark semaphore lock in such a way things work even if fb_alloc_mark() and fb_alloc_free_till_mark() calls are nested. This allows the find_blobs() call-back methods to call py_image.c methods still and also allows us to add more call-backs in the future without worry if we need to. ... Finally, if you have an exception in an interrupt handler all this above breaks terribly. Given MP already breaks if you try to allocate memory in an exception this is a "won't fix problem". Don't call code that can have exceptions or needs memory in an interrupt handler.
This commit is contained in:
parent
9581508bb6
commit
c982617523
@ -12,6 +12,7 @@
|
||||
|
||||
extern char _fballoc;
|
||||
static char *pointer = &_fballoc;
|
||||
static int marks = 0;
|
||||
|
||||
__weak NORETURN void fb_alloc_fail()
|
||||
{
|
||||
@ -23,6 +24,7 @@ __weak NORETURN void fb_alloc_fail()
|
||||
void fb_alloc_init0()
|
||||
{
|
||||
pointer = &_fballoc;
|
||||
marks = 0;
|
||||
}
|
||||
|
||||
uint32_t fb_avail()
|
||||
@ -48,15 +50,18 @@ void fb_alloc_mark()
|
||||
// we will use a size value of 4 as a marker in the alloc stack.
|
||||
*((uint32_t *) new_pointer) = sizeof(uint32_t); // Save size.
|
||||
pointer = new_pointer;
|
||||
marks += 1;
|
||||
}
|
||||
|
||||
void fb_alloc_free_till_mark()
|
||||
{
|
||||
if (!marks) return;
|
||||
while (pointer < &_fballoc) {
|
||||
int size = *((uint32_t *) pointer);
|
||||
pointer += size; // Get size and pop.
|
||||
if (size == sizeof(uint32_t)) break; // Break on first marker.
|
||||
}
|
||||
marks -= 1;
|
||||
}
|
||||
|
||||
// returns null pointer without error if size==0
|
||||
@ -128,4 +133,5 @@ void fb_free_all()
|
||||
while (pointer < &_fballoc) {
|
||||
pointer += *((uint32_t *) pointer); // Get size and pop.
|
||||
}
|
||||
marks = 0;
|
||||
}
|
||||
|
||||
@ -151,6 +151,7 @@ static float calculate_Ta() // ambient temp
|
||||
|
||||
static void calculate_To(float Ta, float *To)
|
||||
{
|
||||
fb_alloc_mark();
|
||||
int16_t *v_ir = fb_alloc(64 * sizeof(int16_t));
|
||||
// Read IR sensor result
|
||||
test_ack(soft_i2c_write_bytes(FIR_MODULE_ADDR,
|
||||
@ -190,6 +191,7 @@ static void calculate_To(float Ta, float *To)
|
||||
To[i] = sqrtf(sqrtf((v_ir_comp/alpha_comp_ij)+Tak4))-273.15f;
|
||||
}
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
}
|
||||
|
||||
static mp_obj_t py_fir_deinit()
|
||||
@ -260,6 +262,7 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
b_ij = xalloc(64 * sizeof(*b_ij));
|
||||
alpha_ij = xalloc(64 * sizeof(*alpha_ij));
|
||||
|
||||
fb_alloc_mark();
|
||||
uint8_t *eeprom = fb_alloc(256 * sizeof(uint8_t));
|
||||
// Read the whole eeprom.
|
||||
test_ack(soft_i2c_write_bytes(FIR_EEPROM_ADDR,
|
||||
@ -336,6 +339,7 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
powf(2,b_i_scale+(3-ADC_resolution));
|
||||
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_const_none;
|
||||
}
|
||||
case FIR_MLX90640:
|
||||
@ -363,6 +367,7 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
error |= MLX90640_SetResolution(MLX90640_ADDR, ADC_resolution);
|
||||
error |= MLX90640_SetRefreshRate(MLX90640_ADDR, IR_refresh_rate);
|
||||
|
||||
fb_alloc_mark();
|
||||
uint16_t *eeprom = fb_alloc(832 * sizeof(uint16_t));
|
||||
error |= MLX90640_DumpEE(MLX90640_ADDR, eeprom);
|
||||
error |= MLX90640_ExtractParameters(eeprom, (paramsMLX90640 *) alpha_ij);
|
||||
@ -370,6 +375,7 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the MLX90640!");
|
||||
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_const_none;
|
||||
}
|
||||
case FIR_AMG8833:
|
||||
@ -441,11 +447,13 @@ mp_obj_t py_fir_read_ta()
|
||||
case FIR_SHIELD: return mp_obj_new_float(calculate_Ta());
|
||||
case FIR_MLX90640:
|
||||
{
|
||||
fb_alloc_mark();
|
||||
uint16_t *data = fb_alloc(834 * sizeof(uint16_t));
|
||||
PY_ASSERT_TRUE_MSG(MLX90640_GetFrameData(MLX90640_ADDR, data) >= 0,
|
||||
"Failed to read the MLX90640 sensor data!");
|
||||
mp_obj_t result = mp_obj_new_float(MLX90640_GetTa(data, (paramsMLX90640 *) alpha_ij));
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return result;
|
||||
}
|
||||
case FIR_AMG8833:
|
||||
@ -468,6 +476,7 @@ mp_obj_t py_fir_read_ir()
|
||||
case FIR_NONE: return mp_const_none;
|
||||
case FIR_SHIELD:
|
||||
{
|
||||
fb_alloc_mark();
|
||||
float *To = fb_alloc(64 * sizeof(float)), *To_rot = fb_alloc(64 * sizeof(float));
|
||||
float Ta = calculate_Ta();
|
||||
float min = FLT_MAX, max = FLT_MIN;
|
||||
@ -496,10 +505,12 @@ mp_obj_t py_fir_read_ir()
|
||||
|
||||
fb_free();
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_obj_new_tuple(4, tuple);
|
||||
}
|
||||
case FIR_MLX90640:
|
||||
{
|
||||
fb_alloc_mark();
|
||||
uint16_t *data = fb_alloc(834 * sizeof(uint16_t));
|
||||
// Calculate 1st sub-frame...
|
||||
PY_ASSERT_TRUE_MSG(MLX90640_GetFrameData(MLX90640_ADDR, data) >= 0,
|
||||
@ -533,6 +544,7 @@ mp_obj_t py_fir_read_ir()
|
||||
|
||||
fb_free();
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_obj_new_tuple(4, tuple);
|
||||
}
|
||||
case FIR_AMG8833:
|
||||
@ -545,6 +557,7 @@ mp_obj_t py_fir_read_ir()
|
||||
float Ta = temp * 0.0625;
|
||||
|
||||
test_ack(soft_i2c_write_bytes(AMG8833_ADDR, (uint8_t [1]){0x80}, 1, true));
|
||||
fb_alloc_mark();
|
||||
int16_t *data = fb_alloc(64 * sizeof(int16_t));
|
||||
test_ack(soft_i2c_read_bytes(AMG8833_ADDR, (uint8_t *) data, 128, true));
|
||||
float To[64], min = FLT_MAX, max = FLT_MIN;
|
||||
@ -569,6 +582,7 @@ mp_obj_t py_fir_read_ir()
|
||||
}
|
||||
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_obj_new_tuple(4, tuple);
|
||||
}
|
||||
}
|
||||
@ -647,6 +661,7 @@ mp_obj_t py_fir_draw_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
mp_obj_t *arg_To;
|
||||
mp_obj_get_array_fixed_n(args[1], width*height, &arg_To);
|
||||
|
||||
fb_alloc_mark();
|
||||
float *To = fb_alloc(width*height * sizeof(float)), min = FLT_MAX, max = FLT_MIN;
|
||||
for (int i=0; i<width*height; i++) {
|
||||
float temp = To[i] = mp_obj_get_float(arg_To[i]);
|
||||
@ -711,6 +726,7 @@ mp_obj_t py_fir_draw_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
}
|
||||
}
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_draw_ir_obj, 2, py_fir_draw_ir);
|
||||
|
||||
@ -6095,11 +6095,13 @@ static mp_obj_t py_image_find_template(uint n_args, const mp_obj_t *args, mp_map
|
||||
// Find template
|
||||
rectangle_t r;
|
||||
float corr;
|
||||
fb_alloc_mark();
|
||||
if (search == SEARCH_DS) {
|
||||
corr = imlib_template_match_ds(arg_img, arg_template, &r);
|
||||
} else {
|
||||
corr = imlib_template_match_ex(arg_img, arg_template, &roi, step, &r);
|
||||
}
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
if (corr > arg_thresh) {
|
||||
mp_obj_t rec_obj[4] = {
|
||||
@ -6130,7 +6132,9 @@ static mp_obj_t py_image_find_features(uint n_args, const mp_obj_t *args, mp_map
|
||||
"Region of interest is smaller than detector window!");
|
||||
|
||||
// Detect objects
|
||||
fb_alloc_mark();
|
||||
array_t *objects_array = imlib_detect_objects(arg_img, cascade, &roi);
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
// Add detected objects to a new Python list...
|
||||
mp_obj_t objects_list = mp_obj_new_list(0, NULL);
|
||||
@ -6209,7 +6213,9 @@ static mp_obj_t py_image_find_keypoints(uint n_args, const mp_obj_t *args, mp_ma
|
||||
#endif
|
||||
|
||||
// Find keypoints
|
||||
fb_alloc_mark();
|
||||
array_t *kpts = orb_find_keypoints(arg_img, normalized, threshold, scale_factor, max_keypoints, corner_detector, &roi);
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
if (array_length(kpts)) {
|
||||
py_kp_obj_t *kp_obj = m_new_obj(py_kp_obj_t);
|
||||
@ -6245,11 +6251,15 @@ static mp_obj_t py_image_find_edges(uint n_args, const mp_obj_t *args, mp_map_t
|
||||
|
||||
switch (edge_type) {
|
||||
case EDGE_SIMPLE: {
|
||||
fb_alloc_mark();
|
||||
imlib_edge_simple(arg_img, &roi, thresh[0], thresh[1]);
|
||||
fb_alloc_free_till_mark();
|
||||
break;
|
||||
}
|
||||
case EDGE_CANNY: {
|
||||
fb_alloc_mark();
|
||||
imlib_edge_canny(arg_img, &roi, thresh[0], thresh[1]);
|
||||
fb_alloc_free_till_mark();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -6270,7 +6280,9 @@ static mp_obj_t py_image_find_hog(uint n_args, const mp_obj_t *args, mp_map_t *k
|
||||
|
||||
int size = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 8);
|
||||
|
||||
fb_alloc_mark();
|
||||
imlib_find_hog(arg_img, &roi, size);
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
return args[0];
|
||||
}
|
||||
@ -7389,6 +7401,7 @@ static mp_obj_t py_image_match_descriptor(uint n_args, const mp_obj_t *args, mp_
|
||||
mp_obj_t match_list = mp_obj_new_list(0, NULL);
|
||||
|
||||
if (array_length(kpts1->kpts) && array_length(kpts1->kpts)) {
|
||||
fb_alloc_mark();
|
||||
int *match = fb_alloc(array_length(kpts1->kpts) * sizeof(int) * 2);
|
||||
|
||||
// Match the two keypoint sets
|
||||
@ -7405,6 +7418,7 @@ static mp_obj_t py_image_match_descriptor(uint n_args, const mp_obj_t *args, mp_
|
||||
|
||||
// Free match list
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
if (filter_outliers == true) {
|
||||
count = orb_filter_keypoints(kpts2->kpts, &r, &c);
|
||||
|
||||
@ -310,6 +310,7 @@ static mp_obj_t py_lcd_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_a
|
||||
return mp_const_none;
|
||||
case LCD_SHIELD:
|
||||
lcd_write_command_byte(0x2C);
|
||||
fb_alloc_mark();
|
||||
uint8_t *zero = fb_alloc0(width*2);
|
||||
uint16_t *line = fb_alloc(width*2);
|
||||
for (int i=0; i<t_pad; i++) {
|
||||
@ -339,6 +340,7 @@ static mp_obj_t py_lcd_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_a
|
||||
}
|
||||
fb_free();
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_const_none;
|
||||
}
|
||||
return mp_const_none;
|
||||
@ -351,11 +353,13 @@ static mp_obj_t py_lcd_clear()
|
||||
return mp_const_none;
|
||||
case LCD_SHIELD:
|
||||
lcd_write_command_byte(0x2C);
|
||||
fb_alloc_mark();
|
||||
uint8_t *zero = fb_alloc0(width*2);
|
||||
for (int i=0; i<height; i++) {
|
||||
lcd_write_data(width*2, zero);
|
||||
}
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_const_none;
|
||||
}
|
||||
return mp_const_none;
|
||||
|
||||
@ -149,15 +149,17 @@ static mp_obj_t py_sensor_alloc_extra_fb(mp_obj_t w_obj, mp_obj_t h_obj, mp_obj_
|
||||
break;
|
||||
}
|
||||
|
||||
fb_alloc_mark();
|
||||
img.pixels = fb_alloc0(image_size(&img));
|
||||
return py_image_from_struct(&img);
|
||||
// Alloc image first (could fail) then alloc RAM so that there's no leak on failure.
|
||||
mp_obj_t r = py_image_from_struct(&img);
|
||||
// Don't mark before on purpose.
|
||||
((image_t *) py_image_cobj(r))->pixels = fb_alloc0(image_size(&img));
|
||||
return r;
|
||||
}
|
||||
|
||||
static mp_obj_t py_sensor_dealloc_extra_fb()
|
||||
{
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
// Don't free till mark aftwards on purpose.
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
|
||||
@ -555,6 +555,7 @@ static mp_obj_t py_tv_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar
|
||||
uint16_t x = x1;
|
||||
uint16_t y = y1;
|
||||
|
||||
fb_alloc_mark();
|
||||
uint8_t *line = fb_alloc(w*2);
|
||||
|
||||
while (y < y2) {
|
||||
@ -586,6 +587,7 @@ static mp_obj_t py_tv_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar
|
||||
y++;
|
||||
}
|
||||
fb_free();
|
||||
fb_alloc_free_till_mark();
|
||||
return mp_const_none;
|
||||
}
|
||||
static mp_obj_t py_tv_palettes()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user