lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Sunday 06, Patrick Donnelly wrote:
> Hi Robert,
>
> On Sun, Sep 6, 2009 at 8:37 PM, Robert G.
>
> Jakabosky<bobby@sharedrealm.com> wrote:
> > On Sunday 06, Luiz Henrique de Figueiredo wrote:
> >> > In my opinion, os.exit() is for exiting quickly and letting the OS
> >> > worry about cleaning up.
> >>
> >> Exactly. Nevertheless, in Lua 5.2, os.exit will accept a flag that tells
> >> whether to close the Lua state.
> >
> > How about an os.atexit(func) function to register Lua functions to called
> > when os.exit() or a normal exit happens.  This way Lua scripts can still
> > do resource cleanup if they need/want to.  Attached 'atexit.lua' is a
> > simple pure Lua os.atexit() function, it catches both 'os.exit()' and
> > normal exit.
> >
> > Personally I am in the camp of people that like to have all
> > memory/resources released by the application/daemon before it exit's back
> > to the OS.  But for simple shell type scripts this is overkill.
> >
> > P.S Yay for money-patching. ;)
>
> Since this can be done in Lua (as you show), why does this need to be
> supported in C?

I think closing the lua_State is the less error prone method of cleanup.  
Since any object that needs to cleanup some complex resource should already 
have a "__gc" method.  I would like to see both the Lua 5.2 os.exit() flag 
and os.atexit().

One use of the os.atexit() function that I can think of is a daemon written in 
pure Lua which creates a pid file when it starts then deletes that file when 
it exits.  Or to just log the error code passed to os.exit(code).

The new version of atexit.lua attached now passes the error code from 
os.exit() to the atexit functions.

-- 
Robert G. Jakabosky
local exit_list={}
local exit=os.exit
local function cleanup(rc)
	-- call atexit functions in reverse order
	for x=#exit_list,1,-1 do
		local func = exit_list[x]
		func(rc)
		exit_list[x] = nil
	end
end
-- catch normal exit.
local gc=newproxy(true)
exit_list.gc = gc
gc=getmetatable(gc)
gc.__gc = function() cleanup(0) end

os.exit = function(rc)
	rc = rc or 0
	cleanup(rc)
	exit(rc)
end
os.atexit = function(func)
	table.insert(exit_list, func)
end

require("atexit")

print("call atexit")
os.atexit(function(rc)
	print("atexit function number 1, rc=" .. rc)
end)
os.atexit(function(rc)
	print("atexit function number 2, rc=" .. rc)
end)
os.atexit(function(rc)
	print("atexit function number 3, rc=" .. rc)
end)
os.atexit(function(rc)
	print("atexit function number 4, rc=" .. rc)
end)

-- GC test.
print "start full GC"
collectgarbage("collect")
collectgarbage("collect")
collectgarbage("collect") -- hehe can't be to sure. ;)
collectgarbage("collect")
print("finished full GC")

rc=arg[1] or nil
if rc ~= nil then
	if rc == '0' then 
		print "call os.exit()"
		os.exit() -- test default error code
	else
		print "call os.exit(rc)"
		os.exit(rc) -- test passing error code.
	end
	print "error error shouldn't get here."
end

print "normal exit no 'os.exit()' call"