Page 1 of 2

thread:pause() ?

Posted: Mon Oct 13, 2014 2:39 pm
by Luke100000
I'm working on a game, where the player can write own code into an virtual computer. Because the main-loop should not stop, a thread is needed. The virtual computers are slow, ~1 MHz. To control them I have an extra thread who only controls all the computers.

Code: Select all

while true do
    local time = os.clock()
    for i = 1, #threads do
        threads[i]:start()
        love.timer.sleep(virtualCPUspeed / realCPUspeed)
        threads[i]:pause() --And here's the problem, there is no pause.
    end
    love.timer.sleep(1 - (os.clock - time) )
end
The computers have every second some time to do their work.

Sorry for my English, I think I made some spelling errors :D

Re: thread:pause() ?

Posted: Mon Oct 13, 2014 7:04 pm
by Nixola
You should implement sleeping inside the thread itself, not outside of it. The thread can't be controlled directly from the outside, you've got to control it from within itself.

Re: thread:pause() ?

Posted: Mon Oct 13, 2014 7:27 pm
by slime
[wiki]Channel:demand[/wiki], [wiki]Channel:supply[/wiki], and [wiki]love.timer.sleep[/wiki] will all pause the thread the functions are called from (until the condition is met.) As Nixola mentioned, you'll need to do it from inside the thread's code rather than outside.

It's also generally a good idea to do a while-loop from inside the thread's code rather than constantly restarting it, since starting a thread is very expensive compared to just continuing a loop (and that gives you a great place to use the above functions to pause the thread.)

Re: thread:pause() ?

Posted: Tue Oct 14, 2014 10:01 am
by Luke100000
How can I do this, so that the player can't delete this love.timer.sleep() ?
The player could use a while-loop!

Can I yield a coroutine automatically after time? Something like this: coroutine:resume(forSeconds)

Re: thread:pause() ?

Posted: Wed Oct 15, 2014 1:00 pm
by Xgoff
Luke100000 wrote:How can I do this, so that the player can't delete this love.timer.sleep() ?
The player could use a while-loop!
unless this is a server program, i wouldn't worry too much about the user shooting their own foot
Can I yield a coroutine automatically after time? Something like this: coroutine:resume(forSeconds)
well, yes and no. unlike pre-emptive threads, coroutines have full control over their own yielding. you *could* write wrappers around the coroutine functions that cause a coroutine to yield itself automatically after some time period, but it will still be vulnerable to infinite loops or even long-running code, again because coroutines are not pre-emptive

Re: thread:pause() ?

Posted: Wed Oct 15, 2014 5:53 pm
by Robin
Actually, now that I think of it, Kikito has written a sandbox library that limits the time a function can run. It might be something you can use.

Re: thread:pause() ?

Posted: Wed Oct 15, 2014 6:08 pm
by Luke100000
OK that's maybe a stupid idea: When the player launch the code, it will create a special love.timer.sleep() in front of every end/else/elseif.

Something like this:

--- original code

Code: Select all

local a = 0
while true do
   if a < 100 then
      a = a + 1
   else
      a = 0
   end
end
-- code after launching

Code: Select all

local a = 0
while true do
   if a < 100 then
      a = a + 1
      wait()
   else
      a = 0
      wait()
   end
   wait()
end
It should work. :awesome:

Xgoff wrote:
Luke100000 wrote:How can I do this, so that the player can't delete this love.timer.sleep() ?
The player could use a while-loop!
unless this is a server program, i wouldn't worry too much about the user shooting their own foot
It's not a server, but there are different in-game-computer with different speed.

Xgoff, did you write "OBEY" in hexadecimal on your avatar? :awesome:

Robin wrote:Actually, now that I think of it, Kikito has written a sandbox library that limits the time a function can run. It might be something you can use.
Yeah that's great. The player can create short lag spikes but it's something I was looking for. At first.

Re: thread:pause() ?

Posted: Wed Oct 15, 2014 7:36 pm
by Robin
Luke100000 wrote:OK that's maybe a stupid idea: When the player launch the code, it will create a special love.timer.sleep() in front of every end/else/elseif.
That sounds exploitable.

If you implement that, I'd like to take a look at that, see if I can find ways to abuse it. :)

Re: thread:pause() ?

Posted: Sat Oct 18, 2014 3:38 pm
by Luke100000

Code: Select all

local lastTime = false
local timewhenstarted = love.timer.getTime()
local time = 0

local CPUspeed = 20 --MHz, the virtual-computer
local realCPUspeed = 3 * 3200 --MHz, my computer

local sleepAfter = CPUspeed / realCPUspeed

function wait()

	local microtime = love.timer.getTime()
	if lastTime then
		time = time + ( microtime - lastTime )
		if time > sleepAfter then
			love.timer.sleep( sleepAfter * ( realCPUspeed / CPUspeed - 1 ) )
			microtime = microtime + sleepAfter * ( realCPUspeed / CPUspeed - 1 )
			time = time - sleepAfter
		end
	end
	
	lastTime = microtime
	if microtime - timewhenstarted > 10 then
		print( "loops per second: " .. math.floor( a/10 ) .. "\n" )
		os.exit()
	end
	
end

function transformCode(code)
	local i = 0
	local functname = "wait()"
	local commandsToCheck = {"end", "else", "elseif"}
	local string = code
	
	for i,v in ipairs(commandsToCheck) do
		while true do
			i, j = string.find(string .. " ", v, i + 2 + #functname)
			if i == nil then
				break
			end
			string = string.sub(string, 1, i - 1) .. functname .. " " .. string.sub(string, i, #string)
		end
	end
	
	--remove all \n
	while true do
		i, j = string.find(string, "\n")
		if i == nil then
			break
		end
		string = string.sub(string, 1, i-1) .. " " .. string.sub(string, i+1, #string)
	end
	
	return string
end

local original_code = "a = 0\nwhile true do\n    a = a + 1\nend"

local code = transformCode( original_code .. " " )

print("\nORIGINALCODE:\n" .. original_code .. "\n\nCODE:\n" .. code .. "\n")

local func, msg =  pcall( loadstring( code ) )

if func then
	func()
else
	print("ERROR: " .. msg)
end
original_code is the code which can be written by the player. Because the player can write several lines, my "transformCode()" delete all "\n"
realCPUspeed is your PC, I need a library to check this automatically :(
CPUspeed is the speed of the ingame-computer. I type 20 MHz, this is very slow.
For this example, I will stop the code in the wait() function and print out the progress.

Re: thread:pause() ?

Posted: Sat Oct 18, 2014 6:42 pm
by Robin
Why do you remove all \n, tough?

Also, both adding wait() and removing \n could be done with simply calling [manual]string.gsub[/manual] instead of those expensive
Also:

Code: Select all

function wait() end
local a = 0
while true do
   if a < 100 then
      a = a + 1
   else
      a = 0
   end
end
Also, this way I can't use return anywhere, I don't know if that's intended.