Repository navigation
persistentcode.c: save_raw_code() - add flush/finalizer callback #3478
Description
Activity
- changed the title
[-]persistentcode.c: save_raw_code() - add finalizer[/-][+]persistentcode.c: save_raw_code() - add flush callback[/+]on Dec 8, 2017 - changed the title
[-]persistentcode.c: save_raw_code() - add flush callback[/-][+]persistentcode.c: save_raw_code() - add flush/finalizer callback[/+]on Dec 8, 2017 The function that calls
save_raw_code()(actually that callsmp_raw_code_save()) should be responsible for doing any finalisation of the stream. For example,mp_raw_code_save_file()closes (and implicitly flushes) the file once done.For example, mp_raw_code_save_file() closes (and implicitly flushes) the file once done.
I think you made my point with this example: I agree that it makes sense for
mp_raw_code_save_file()to callclose(fd). For that same reason,mp_raw_code_save()should also call the finalizer: either the finalizer is called by the caller ofmp_raw_code_save*()or it's called inside said function.I agree that it makes sense for mp_raw_code_save_file() to call close(fd). For that same reason, mp_raw_code_save() should also call the finalizer:
I don't see how this logically follows.
mp_raw_code_save()is essentially a helper function and the caller of it should finalise the stream, because the caller knows best how to do finalisation.mp_raw_code_save_file()calls the finalizerclose()so why shouldn’tmp_raw_code_save()call a finalizer?In the same way that
mp_print_tprovides the interface to “print” which needs to be set to an actual “print” function,mp_print_tshould also contain an interface to finalize (as I mentioned in the first post to this issue)typedef void (*mp_print_strn_t)(void *data, const char *str, size_t len); typedef void (*mp_print_flush_t)(void *data); typedef struct _mp_print_t { void *data; mp_print_flush_t print_flush; mp_print_strn_t print_strn; } mp_print_t;mp_raw_code_save_file() calls the finalizer close() so why shouldn’t mp_raw_code_save() call a finalizer?
Becasue
mp_raw_code_save_file()can do it and there's no need to burden the core routine with a finaliser call.In your specific case, it looks like it should work just fine to flush the output at the very end (ie not in
mp_raw_code_save()).- added a commit that references this issue
on Sep 29, 2020 mp_raw_code_save()is a mid-level API function (eg you may want to call it twice in a row to save 2 separate raw codes). Higher-level API functions built on top of this function are responsible for flushing/closing the stream, eg:void mp_raw_code_save_flash(...) { mp_raw_code_save(...); commit_to_flash(); }
micropython/py/persistentcode.c
Lines 319 to 371 in e9d29c9
mp_raw_code_saveneeds a finalizing call for the case ofprintbeing a function that saves to flash (or more generally, an implementation that needs a manual flush).Flash can only be written one page at a time so unless all calls to
printjust happen to have a cumulative number of bytes equal to a multiple of the page size . . .printwill be stuck waiting for the last (page_size_bytes - buffer_curr_num_bytes) bytes forever.The simplest way to implement this flush is to call
print->print_strnwithNULLfor data and0for length (unless someone can think of valid use for those set of arguments).print->print_strn(print->data, (const char*)NULL, 0);But the cleaner way would be to add a member to
mp_print_tmicropython/py/mpprint.h
Lines 48 to 53 in e9d29c9
And the very last statement in
mp_save_raw_codeissave_raw_code_flush(print)If your implementation of
mp_print_t *printdoesn't need a finalizer, you can just setprint->print_flush = NULL.