- Sky
- Blueberry
- Slate
- Blackcurrant
- Watermelon
- Strawberry
- Orange
- Banana
- Apple
- Emerald
- Chocolate
- Charcoal
-
Content Count
172 -
Joined
-
Last visited
-
Days Won
14
Posts posted by payonel
-
-
If my last response was too heavy handed I apologize. I'm just passionate about OpenOS and I care about how it works and how it is used. Perhaps what OpenOS needs is a way for a program to register hard interrupt handlers. But until then..pcalls, coroutines, or threads
-
Soft interrupts are already passed as an event
We're talking about hard interrupts, which are designed to abort a process, like a SIG* in linux-land. It's worse than "not ideal". It's bad form and a slippery slope.
My point is that this is not the correct way to use OpenOS in user code.
I cannot agree that changing os behavior as a by-product of a user program is OK. If you want to make a variation of OpenOS, or consider your library a patch to the OS, that's different. As this is not how the libraries should be used, I would classify this more of a KERNEL change.
-
I don't know the code, but I bet
oop.inherit(bar_base, frame_base);
Sets a metatable on bar_base that provides a getSize method from from_base, so find the code in
local frame_base = require("libGUI/frame");
-
Oh I would prefer people DO NOT override system methods such as event.*
Please
Hard interrupts are thrown as exceptions, use pcall or xpcall to capture events. Note that interrupts are not checked until you yield for computer signals
Examples:
- coroutine.yield() out of your program will yield for the next computer signal
- literally calling computer.pullSignal or event.pull will yield
- os.sleep
If during these "yields" the user is pressing ctrl+shift+c, a hard interrupt exception is thrown and your program will abort if uncaught. Thus, if you have code that you do not want interrupted, don't put yields inside of it.
Soft interrupts are just plain events, if you ignore or do not handle them, they do nothing
-
the real "how to print to screen" work is done in a kernel level library called tty. These are NOT public methods because the method names and parameters will change without warning as I see fit to optimize or refactor code. But, if you want to know where "print" EVENTUALLY gets to actually rendering text on the screen, look here: https://github.com/payonel/OpenComputers/blob/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/openos/lib/tty.lua#L319
The boot code has a far simpler, dumbed down version (for example, it doesn't wrap, it doesn't have a cursor position): https://github.com/payonel/OpenComputers/blob/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/openos/lib/core/boot.lua#L45
-
Also see the new thread library which can solve the "I need to event.pull without blocking other parts of my code": http://ocdoc.cil.li/api:thread
-
Also, io.open takes RELATIVE or ABSOLUTE paths, ALL FILESYSTEM API methods ASSUME absolute paths
e.g.
require("filesystem").open("file.txt") opens /file.txt
not /your/current/path/file.txt
compare to
io.open("file.txt") opens /your/current/path/file.txt
-
loadstring is depcrated in Lua 5.2, and obsolete (removed, gone) in Lua 5.3
load(text)() works equivalently
https://www.lua.org/manual/5.2/manual.html#8.2
-
OpenOS provide threads now, see http://ocdoc.cil.li/api:thread
-
In this response when I say "In EERPROM" I am referring to any code that is running without or before OpenOS. It doesn't necessarily have to be literally in EEPROM code. It could be your own custom OS, it could be literally code in an EEPROM.
So....
require("filesystem") ~= require("component").filesystem
We are dealing with some confusion here. I should make a wiki page specifically about the two weird+confusing things here
We need to understand what is a library and what is a proxy
- require() returns libraries
- component.proxy() and component[component_type_name] provide access to component proxies
Let's first talk about what is true BEFORE OpenOS boots, or in other words, what is true in EEPROM. Keep in mind, OpenOS doesn't do anything you can't do. OpenOS fully runs in the game environment
In EEPROM, The `component` object is available globally, in _G. From here on, let's refer to this component that is in _G in EEPROM as _G.component. The docs really need clarification on this object. This is partially true http://ocdoc.cil.li/api:component
The problem with the "api:component" page is that it describes OpenOS' version of component which is almost the same, but OpenOS adds a few methods and helpers. ocdoc pages that are named "api:" are referring to libraries. And like all other libraries, you need to call require("component") to use that api. So it looks like a library, and it has a library ocdoc page, BUT .. _G.component is available to your EEPROM code (i.e. before OpenOS loads). In truth _G.component and require("component") are the SAME object, but OpenOS adds a few methods to component and OpenOS removes it from _G, thus requiring that you require it.
Every filesystem component (e.g. hdds, floppies) have a GUID (let's call it fs_addr). As for other component types, you can acquire a proxy to that component by calling _G.component.proxy(fs_addr) (or require("component").proxy(fs_addr) when in OpenOS)
local fs_proxy = _G.component.proxy(fs_addr)
Yes I know it is not necessary to use _G but I am trying to make it clear I am referring to the _G.component that is available In EEPROM (or, before OpenOS loads or in any custom boot)
This fs_proxy is a proxy to the actual hdd or the actual floppy in your computer. See http://ocdoc.cil.li/component:filesystem
fs_proxy is a proxy to the component, in linux terms, it is the filesystem DEVICE.
## Libraries ##
OpenOS adds libraries. OpenOS provides a library named filesystem. It has been debated whether this was a good name, given that there is also a component with the SAME NAME.
require("filesystem") is the "filesystem" library api
require(lib_name) returns apis, code from /lib/${lib_name}.lua
and require("filesystem") loads the code from /lib/filesystem.lua, see http://ocdoc.cil.li/api:filesystem
This, the OpenOS filesystem library, can create mounts, can create symbolic links, can open/create/read/write files across all mounted filesystem components (devices).
Lastly, I want to mention that once inside OpenOS, you have NEW methods of acquiring the component proxies.
For example, component.filesystem is a proxy to the "primary" filesystem. This is NOT the rootfs, it is simply the first filesystem component that is detected during boot. Read more about primary components on the api:component page: http://ocdoc.cil.li/api:component
"primary" is an OpenOS idea. Because generally there are multiple filesystem components (even the tmp filesystem is its own filesystem), it is unclear which filesystem you are accessing when you use component.filesystem. I advice you DO NOT use component.filesystem unless you are certain there is only one filesystem. The same argument can be made against using component.proxy(component.list("filesystem")()) -- this is a simple way to get some random filesystem, but you don't know which filesystem.
-
in your sample code you create a coroutine, but you never resume it. Coroutines run like function calls, and yields are like having multiple returns points in said method. The solutions provided are good solutions, but i just wanted to point out that your original code has the right idea, you were just expecting that your code would run two sections autonomously and in parallel, which is possible with threads (we have threads in OpenOS now)
your original sample of code would work just find if you replace
coroutine.create(keyCheck)
with
local thread = require("thread") thread.create(keyCheck)
read more info here: http://ocdoc.cil.li/api:thread
-
eeprom is not a filesystem, it is an eeprom
filesystems can create files via open
eeprom only has 2 data storage areas
> 1. eeprom.get() + eeprom.set() -- this is the code that is run by boot. it's like one large file
> 2. eeprom.getData() + eeprom.setData() -- this is a small data field meant to store persistent data like "which hard drive has the OS"
Graphics are done by the gpu component. In eeprom you could get the first gpu using:
local gpu = component.list("gpu")()
When that you can make all the gpu calls, see: http://ocdoc.cil.li/component:gpu
You do not need any special function name for the bios to start, the machine simply loads the string returned by component.eeprom.get() [ component.eeprom is an object that exists for convenience, made available by openos ]
if you are running OpenOS, you can edit the eeprom data directly:
-- assuming OpenOS shell /home # edit /dev/eeprom
-
Allow me to comment on this code suggestion:
On 6/10/2017 at 2:43 PM, Gorzoid said:filesystem.open or io.open used like this
local io = require("io") local f = io.open("file.txt","w") f:write("file contents") f:close()
You do not need to require("io"), it is a global library
and I recommend using io.open
1. the read/write is buffered (more options, better perf)
2. the path is relative, fs.open is always absolute
read more here: http://ocdoc.cil.li/api:non-standard-lua-libs#input_and_output_facilities
-
you don't need to require("io"), that is a global library
you don't need to require("term") simply because you weren't using it
-
any file you create is created on the host machine, it has nothing to do with openos, but OC doesn't create empty dirs for those.
The idea is that each filesystem component (e.g. a floppy) will have a GUID, files created in that filesystem are created on the host (real) using that GUID as a dir name, with a path to your file.
So, in term of the filesystem api ( see http://ocdoc.cil.li/component:filesystem )
Assuming you have a proxy to a filesystem (this complexity is hidden behind the io library provided by OpenOS):
local filesystem_address = "deadbeaf-..." -- some filesystem component GUID local fs_proxy = component.proxy(filesystem_address) local file_handle = fs_proxy.open("data.dat", "w") -- open file fs_proxy.write(file_handle, "some data to store in the file") fs_proxy.close(file_handle) -- close the file
This creates the file on the host system, AND will create the GUID-named folder to store it (see world/opencomputers/${GUID}/data.dat )
-
OpenOS already fires an event called "shutdown" when computer.shutdown is called. Please don't override any system methods, nor add metatables to nor remove metatables from system libraries.
However, pressing the power button on the machine, losing power, or breaking -- do not send any such signal
-
There is no require provided by the `computer`because there is no default "filesystem", but only filesystems provided by the filesystem components. That is why OpenOS defines require:
-
Also, there is a "
redstone_changed" event that is fired when the input changes. So...the monitor_thread could be a bit cleaner without the sleep, but instead:
local monitor_thread = thread.create(function() while true do if redstone.getBundledInput(sides.back, colors.magenta) then break end event.pull("redstone_changed") end end)
You could also do something quite different with `event.listen`:
local thread = require("thread") local component = require("component") local sides = require("sides") local colors = require("colors") local redstone = component.redstone local user_input_thread = thread.create(function() io.write("waiting for input: ") io.read() end) event.listen("redstone_changed", function() if redstone.getBundledInput(sides.back, colors.magenta) then user_input_thread:kill() return false -- return false removes this event listener from the event registration pool end end) -- user_input_thread will block this process from closing -- but you could optional block on the thread explicitly: -- user_input_thread:join()
I personally like the thread-only solution more than the event.listener solution
-
OpenOS 1.6.5 introduces threads: http://ocdoc.cil.li/api:thread
The examples at the end of that wiki page demonstrate how you could cancel io.read due to some condition: http://ocdoc.cil.li/api:thread#thread_interrupt_handler_example
So for your case:
local thread = require("thread") local component = require("component") local sides = require("sides") local colors = require("colors") local redstone = component.redstone local monitor_thread = thread.create(function() while true do if redstone.getBundledInput(sides.back, colors.magenta) then break end os.sleep(0) end end) local user_input_thread = thread.create(function() io.write("waiting for input: ") io.read() end) thread.waitForAny({monitor_thread, user_input_thread}) io.write("program closing\n") os.exit(0) -- kills all remaining threads
I use `os.exit(0)` because threads that are still running block the parent process from closing (keep it running). It is a good idea to please read the wiki page I wrote on threads.
Another option instead of `os.exit(0)` in this case would be to kill the threads:
thread.waitForAny({monitor_thread, user_input_thread}) monitor_thread:kill() user_input_thread:kill()
-
I"m a new patreon (looks like it's just two of us)
My donation is pathetically small ($1/month) - Sangar and those that help him deserve so much more.
When I start spending more time using OC, I should increase my patreon to match.
Truly great work, Sangar. Thank you so much. Not only is your mod work fantastic, you're kind to your fans, and you make your work open and easily configurable. Truly the perfect example of a great mod for the community.
Sincerely,
Payo
Yield a coroutine from outside of child function for a scheduler
in Programming
Posted
simply put, you cannot.
All threading must be cooperative; everyone must yield on their own.
However, you should know that OpenOS now has threads! [ in case you are wondering how, threads intercept yields and computer.pullSignal and hide the cooperative layer from the user ]
There is actually quite a lot that went into developing threads for OpenOS. Please consider the wiki doc I wrote up about them, and please provide feedback and questions! Any issues or bugs you run into, please use github to create a new issue.
http://ocdoc.cil.li/api:thread