import processing
from threading import local
import stackless
import time

_locals = local()
running = True

def Sleep(secondsToWait):
    channel = stackless.channel()
    endTime = time.time() + secondsToWait
    _locals.sleepingTasklets.append((endTime, channel))
    _locals.sleepingTasklets.sort()
    # Block until we get sent an awakening notification.
    channel.receive()

def ManageSleepingTasklets(threadID):
    global running

    _locals.sleepingTasklets = []
    while running:
        if len(_locals.sleepingTasklets):
            endTime = _locals.sleepingTasklets[0][0]
            if endTime <= time.time():
                channel = _locals.sleepingTasklets[0][1]
                del _locals.sleepingTasklets[0]
                # We have to send something, but it doesn't matter what as it is not used.
                channel.send(None)
        elif stackless.getruncount() == 1:
            # Give up if there are no more sleeping tasklets.  Otherwise the two
            # threads keep on running endlessly.
            break
        stackless.schedule()

def processManagerTasklet(processID, q):
    global running
    while running:
          if not q.empty():
             func, args = q.get()
             print "Process", processID, "received task", func, args
             t = stackless.tasklet(func)(*args)
          stackless.schedule()
          
def processSpawner(processID, q):
    stackless.tasklet(ManageSleepingTasklets)(processID)
    stackless.tasklet(processManagerTasklet)(processID, q)
    stackless.run()
    print "Exit process", processID


#--------------------------

processesChannels = {}
mainTasks = processing.Queue()

n_cores = processing.cpuCount()
core = 1

for n in range(1, n_cores):
    n = n+1
    processesChannels[n] = processing.Queue()


def mainManager():
    global running
    while running:
          #print "Main waiting tasks, active core:", core
        if not mainTasks.empty():
            func, args = mainTasks.get()
            print "Main received task...", func, args
            t = stackless.tasklet(func)(*args)
        else:
            stackless.schedule()
               
    print "Exiting main manager"
    running = False
             
def new(func, *args, **kw):
    global core
    print "Sending task to core:", core
    if core == 1:
        mainTasks.put((func, args))
    elif core > 1:
        processesChannels[core].put((func, args))

    if core < n_cores:
        core += 1
    elif core == n_cores:
        core = 1

def run():
    for n in range(1, n_cores):
        n = n+1
        p = processing.Process(target=processSpawner, args=[n, processesChannels[n]])
        p.start()
    stackless.tasklet(ManageSleepingTasklets)(1)
    stackless.tasklet(mainManager)()
    stackless.run()
