Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal

payonel

Developer
  • Content Count

    172
  • Joined

  • Last visited

  • Days Won

    14

Posts posted by payonel

  1. 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

     

  2. 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.

     

  3. 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");
  4. 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:

    1. coroutine.yield() out of your program will yield for the next computer signal
    2. literally calling computer.pullSignal or event.pull will yield
    3. 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

     

  5. 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

  6. 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

    1. require() returns libraries
    2. 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.

  7. 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

  8. 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

     

  9. 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

  10. 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 )

     

  11. 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

  12. 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

     

  13. 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()

     

  14. 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

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.