-
Notifications
You must be signed in to change notification settings - Fork 3.5k
WasmFS JS API: Implement utime #19561
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WasmFS JS API: Implement utime #19561
Conversation
test/fs/test_fs_js_api.c
Outdated
| assert(ex.name === 'ErrnoError' && ex.errno == 8 /* EBADF */); | ||
| ); | ||
|
|
||
| /********** test FS.utime() **********/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if its worth splitting this function up. (That way the ones that are JS-only can also be written using EM_JS instead of EM_ASM)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Can be a followup PR for that)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify, do you mean splitting up by moving each test section into an EM_JS function? Or should the code be split some other way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup thats what I meant. Each section could be its own function (either a regular C function or an EM_JS function)
system/lib/wasmfs/file.h
Outdated
|
|
||
| struct timespec ts; | ||
| clock_gettime(CLOCK_REALTIME, &ts); | ||
| atime_nsec = mtime_nsec = ctime_nsec = ts.tv_nsec; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is more comprehensive to support nanoseconds as well, and I think this the right way to do it (but we could also get the non-nanosecond times from this as well, to save the previous time(..) call).
However, I think we need to consider if we want to add ns. Technically a POSIX-compliant FS doesn't need that (I don't think POSIX guarantees a particular precision). And on the Web the timing info we get from Date.now() etc. may have limited resolution anyhow.
And, adding ns support has a cost in terms of code size. So overall I lean towards not adding it, and just documenting that decision.
@tlively what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to removing the previous time call.
I would lean toward keeping this. I don't think it's too much of a stretch to imagine an Emscripten application that would want at least millisecond precision in the time stamps. For example, anything doing something similar to make to figure out when file changes mean something needs to be recomputed would need more than second precision.
I also expect that the code size increase would be fairly small.
system/lib/wasmfs/file.h
Outdated
| time_t getATime() { return file->atime; } | ||
| long getATimeNs() { return file->atime_nsec; } | ||
| void setATime(time_t time) { file->atime = time; } | ||
| void setATimeNs(long time) { file->atime_nsec = time; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can combine these getters and setters? I imagine that usually the seconds and nanoseconds will always be set or retrieved at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I was worried about compatibility with any code that used the old getters/setters by getting just the seconds with time(NULL). Would it be worth switching all of them to use a combined getter/setter? If so, would it be better to pass in the seconds and nanoseconds together as a pointer to a struct or two separate time_t and long values respectively?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, switching all the use sites would be fine. There shouldn't be many of them, and this is private API so this wouldn't be a breaking change. I would implement it by passing the timeval struct by value (rather than by pointer) since it is so small.
system/lib/wasmfs/file.h
Outdated
| ts.tv_sec = file->ctime; | ||
| ts.tv_nsec = file->ctime_nsec; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we stored the times on the file as timespecs, then this could just be return file->ctime;.
| test_fs_utime(); | ||
| test_fs_rmdir(); | ||
| test_fs_close(); | ||
| test_fs_mknod(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, I think this makes the test much easier to read.
|
Currently my implementation has failed |
|
Can you run those tests with |
system/lib/wasmfs/file.cpp
Outdated
| setMTime(time(NULL)); | ||
| struct timespec ts; | ||
| clock_gettime(CLOCK_REALTIME, &ts); | ||
| setMTime(ts); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to avoid this repeated code pattern somehow. If we did that then we would have a single place to change if we decided to get time information in another way in the future.
One option might be an updateMTime method which would mean "update to the current time". There might be a better name though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree - would it also be helpful to have these "update to current time" functions for atime and ctime? Or is this only really needed for mtime?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For symmetry it might be nice to have it for them all, even if mtime is the most-repeating pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option might be "updateTime" without mentioning mtime at all. Basically "this file was modified, update whatever time changes need to be done".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thinking making one "update to current time" for each time might be a good option here, since there were a few other spots where only atime and ctime also had to be set to the current time. Would that be fine for now?
src/library_wasmfs.js
Outdated
| }, | ||
| // TODO: utime | ||
| utime: (path, atime, mtime) => { | ||
| return FS.handleError(withStackSave(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove the return here and the curly brace before it. Similar to #19614
| #include <assert.h> | ||
| #include <fcntl.h> | ||
|
|
||
| EM_JS(void, test_fs_open, (), { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe make a separate PR for the test refactorings of existing tests?
| @@ -1 +1 @@ | |||
| 51960 | |||
| 52403 | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the cost of supporting nanoseconds, I suppose?
I am not sure it's worth it, personally. 500 bytes isn't a lot, but the benefit is unclear to me... but if you feel strongly @tlively I don't object.
Regardless, if we decide we want nanoseconds let's do it in its own PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think having better than second precision is worth 500 bytes. I'm surprised it costs that much, though.
This PR refactors test_fs_js_api by placing each test into a separate method. This PR was split from #19561
tlively
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM % stale TODOs.
|
Is this ready to land? (it's still marked "draft") |
|
Oops, I forgot to set it as "ready" but the branch is ready to land. |
This PR adds nanosecond support for file times in WasmFS, specifically when used for utime and stat. This PR was separated from #19561
This PR implements
utimefor the JS API. I didn't find any tests forutimein the test directory, so added tests totest_fs_js_api.I also attempted to add support for
atime,mtime, andctimenanoseconds in WasmFS. I am still a little new to C++ programming, so please let me know about any improvements I need to make to the implementation. One thing I wasn't sure about was how to get the nanoseconds - is using#include <time.h>the best way?