This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
ElvishJerricco's profile picture

A daemon solution v1.2.1 Now with -list, -kill, and -s.

Started by ElvishJerricco, 27 January 2013 - 05:30 AM
ElvishJerricco #1
Posted 27 January 2013 - 06:30 AM
A daemon in computer science is a background task. Traditionally, Lua doesn't do this too well. But I think I've built a nice solution for this.

As soon as you run this program, a new shell will be started. This shell can be used normally. Now you can add daemons to the background.


daemon.loadDaemon("My Daemon", function()
	-- Code to do stuff.
end)

daemon.loadDaemon(stringName, func) is how you load a daemon. You create a function that you want to run in the background, and load it. In the example above, I declared the function within the loadDaemon call, but you can create the function before hand also.

This is particularly useful for APIs that need tasks to keep running.


--MyApiFile
if daemon then
	local lastMessage

	function getLastMessage()
		return lastMessage
	end

	function myDaemon()
		while true do
			local id, msg = rednet.receive()
			lastMessage = msg
		end
	end

	daemon.loadDaemon("My Daemon", myDaemon)
else
	print("This API requires the Daemon Server by ElvishJerricco")
end

Now you can call MyApiFile.getLastMessage() to retrieve the most recent rednet message. This is obviously a very basic example but it works and it demonstrates just what the daemon server can do.

To stop the daemon server, run the program again with the argument -stop or call daemon.stopServer(). Also, running <filename> -list will list all running daemons by their IDs and names. Using <filename> -kill <ID> will kill the daemon with the specified ID. Using <filename> -s will launch the daemon server and run startup when the new shell starts.

Note: no matter what you name this file, the API for loadDaemon() is ALWAYS called daemon. So no matter what, the code is daemon.loadDaemon(stringName, func).

2nd Note: I strongly urge you to use os.pullEventRaw instead of os.pullEvent from within your daemons. Because of the way termination works, it's very tricky to predict how a daemon will react to this, if at all.

pastebin get MtkSVDWH startd

Changelog
Spoilerv1.2.1
  • Added -s option. Launches startup in the new shell.
v1.2
  • daemon.loadDaemon(stringName, func) now has an argument for the name of the daemon.
  • Added -list option. Will list all daemons currently running.
  • Added -kill option. Will kill the targeted daemon.
  • Added daemon.getDaemonIDsNames(). Returns a table of daemon names with their IDs as keys.
  • Added daemon.killDaemonByID(id). Kills the daemon with that ID.
  • Modified the help option to scroll since it's now too long for one page.
v1.1
  • Ctr+T now works.
  • Calling daemon.stopServer() will stop the server.
  • Using the command argument -stop will stop the server.
v1.0
  • Initial release.
etopsirhc #2
Posted 27 January 2013 - 07:16 AM
now this looks interesting =0

but how would you communicate with the daemon?
ElvishJerricco #3
Posted 27 January 2013 - 07:33 AM
now this looks interesting =0

but how would you communicate with the daemon?

Well the idea is to have everything setup and then the daemon is just kindof a driver for that. So you could either have a program that has a bunch of functions and variables for it to use, and one of those functions is a daemon. Or you could do as I described above and have a function from an API be turned into a daemon. With the API method, you can have any and all programs do work with the daemon.
tesla1889 #4
Posted 28 January 2013 - 06:44 AM
the problem is, when you run /rom/programs/shell again, the program automatically forks the shell, because the first shell has already been loaded.

the only way to do this is to modify /rom/programs/shell

EDIT: forgot to say, brilliant concept though. i'm sure it will be easy to edit the shell program to do this
ElvishJerricco #5
Posted 28 January 2013 - 07:23 AM
the problem is, when you run /rom/programs/shell again, the program automatically forks the shell, because the first shell has already been loaded.

the only way to do this is to modify /rom/programs/shell

EDIT: forgot to say, brilliant concept though. i'm sure it will be easy to edit the shell program to do this

Actually, the only time a shell is forced to have a parent shell is when you use shell.run("shell"). If you use os.run({}, "rom/programs/shell"), no shell is launching the new shell, so no parent shell is set.
tesla1889 #6
Posted 28 January 2013 - 11:29 AM
ah. didn't catch the os.run instead of shell.run

another way you could do it is

local oldshell = shell
shell = nil
oldshell.run("/rom/programs/shell")
daemon = shell
shell = oldshell
ElvishJerricco #7
Posted 28 January 2013 - 01:35 PM
ah. didn't catch the os.run instead of shell.run

another way you could do it is

local oldshell = shell
shell = nil
oldshell.run("/rom/programs/shell")
daemon = shell
shell = oldshell

I don't actually think that would work. When a program is launched, it is in an environment whose shell variable is set to the shell. Changing the value assigned to the key "shell" in your program doesn't actually change the shell variable at all. Your variable oldshell is going to still provide itself as a parent shell to the shell you're starting.
NeverCast #8
Posted 28 January 2013 - 01:54 PM
alternatively you could change the environment of the call to os.run and remove shell so there is no parent shell.