~vdupras/duskos

a1a541c8dc15f42598ea90fbda23def37e555a96 — Virgil Dupras 14 days ago e4e5ea4
Make "floaded," a noop if FSID is already loaded
3 files changed, 35 insertions(+), 13 deletions(-)

M fs/doc/lib/meta.txt
M fs/sys/file.fs
M fs/xcomp/bootlo.fs
M fs/doc/lib/meta.txt => fs/doc/lib/meta.txt +28 -7
@@ 40,13 40,7 @@ forget ( "name" -- )
  In other words, make the system forget everything that happened since "name"
  was defined.

  WARNING: not all "forget" operations are clean. In fact, many "forget"
  operations are unclean. Use with care. For example, context switching (see
  lib/context) and forgetting don't go well together. Arena memory allocation
  (see lib/alloc) and forgetting don't go well together.

  The forget operation is useful in many situations, but be aware of its effects
  when you use it.
  WARNING: not all "forget" operations are clean. See section below.

Words related to metadata's linked list:



@@ 63,3 57,30 @@ findmeta ( typeid meta -- meta-or-0 )
.doc ( word -- )
  Print the docstring metadata associated with "word".

## Forgetting is tricky

The forget operation is useful in many situations, but be aware of its effects
when you use it!

Not all "forget" operations are clean. In fact, many "forget" operations are
unclean. Use with care. For example, context switching (see lib/context) and
forgetting don't go well together. Arena memory allocation (see lib/alloc) and
forgetting don't go well together.

Another tricky example is "floaded,", the mechanism for remembering which files
were loaded or not, what makes ?f<< work. This is a LL where new elements are
written to "here". When you forget past the latest "floaded" point, you break
the whole chain, leading to memory corruption.

However, it's a common pattern, when working on a file, to load it, try it, then
forget it, then load it again and so on. This will work, but be aware of these
facts:

1. The "floaded" node is written to "here" *before* the file is actually loaded.
2. "f<<" does not add a node if the node is already present.

Therefore, you can have a "f<< / forget" loop if you always load the same single
file. If you really need to load multiple files, you'll need to "pre-mark" your
files as loaded with something like 'p" /my/path" Path id floaded,' and then
individually load your files with "f<<" (implicit "?f<<" won't load anything).
Your loaded files will then be "forget-safe".

M fs/sys/file.fs => fs/sys/file.fs +1 -4
@@ 79,10 79,7 @@ struct[ Path
  : :find# ( str -- path )
    :find ?dup not if abort" path not found" then ;

  : :floaded? ( self -- f )
    id floaded begin ( id ll )
    ?dup while 2dup CELLSZ + @ = not while llnext repeat
    2drop 1 else drop 0 then ;
  : :floaded? ( self -- f ) id floaded? ;
  : :chdir ( self -- )
    dup id _curpath CELLSZ + !  fs _curpath ! ;
  : :fload ( self -- ) dup fs swap id fload ;

M fs/xcomp/bootlo.fs => fs/xcomp/bootlo.fs +6 -2
@@ 332,8 332,12 @@ extends IO struct[ File

\ File loading
\ TODO: support loading from multiple FSes.
create floaded 0 , \ address of the current "loaded file" structure
: floaded, ( id -- ) floaded lladd drop ( id ) , ;
create floaded 0 , \ loaded files LL, *no data*
: floaded? ( id -- f )
  floaded begin ( id ll )
    llnext ?dup while 2dup CELLSZ + @ = not while repeat
    2drop 1 else drop 0 then ;
: floaded, ( id -- ) dup floaded? if drop else floaded lladd drop , then ;
: \s console readio IO :close ;
: fload ( fs id -- )
  dup floaded, swap Filesystem :open ( hdl )