Skip to content

Instantly share code, notes, and snippets.

@nsf
Created January 14, 2016 17:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nsf/a7a85e8c742be965399a to your computer and use it in GitHub Desktop.
Save nsf/a7a85e8c742be965399a to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
using System.Collections.Generic;
namespace NG.Tasks {
public class Counter {
public int Count = 0;
/// Task that waits on this counter.
public Task WaitingTask;
public Counter(int num) {
Count = num;
}
}
public enum CoType {
Continue,
Yield,
Done,
WaitForCounter,
WaitForSemaphore,
WaitForMessage,
}
public class Out<T> : IOut<T> {
public T Value { get; set; }
}
public class CallbackOut<T> : IOut<T> {
Action<T> cb;
public CallbackOut(Action<T> cb) {
this.cb = cb;
}
public T Value { set { cb(value); } }
}
public interface IOut<T> {
T Value { set; }
}
public struct Co {
public CoType Type;
public object Subject;
public C.CSMessage Message;
/// Continue execution.
public static readonly Co Continue = new Co{ Type = CoType.Continue };
/// Stop execution of the current coroutine.
public static readonly Co Done = new Co{ Type = CoType.Done };
// Put the current coroutine to the end of the queue.
public static readonly Co Yield = new Co{ Type = CoType.Yield };
/// Lock a mutex, possibly putting the current coroutine on hold if the mutex was locked by another coroutine.
public static Co Lock(Mutex m) {
return m.Lock();
}
/// Unlock a mutex. Will schedule a coroutine for execution if there is one in internal queue.
public static void Unlock(Mutex m) {
m.Unlock();
}
/// Schedule task for execution.
public static void Go(Task task) {
Scheduler.Go(task);
}
/// Schedule task for execution.
public static void Go(IEnumerator<Co> task) {
Scheduler.Go(new Task(task));
}
/// Schedule task for execution with specified parameters.
public static void Go(IEnumerator<Co> task, TaskParameters tp) {
Scheduler.Go(new Task(task, tp));
}
/// Schedule task for execution.
public static void Go(Action action) {
Scheduler.Go(new Task(action));
}
/// Schedule task for execution with specified parameters.
public static void Go(Action action, TaskParameters tp) {
Scheduler.Go(new Task(action, tp));
}
static Task ToTask(IEnumerator<Co> task) {
return new Task(task);
}
/// Runs tasks and waits for their completion.
public static Co WaitFor(IEnumerator<Co>[] tasks) {
return Scheduler.WaitFor(tasks.Select(ToTask).ToArray());
}
/// Runs tasks and waits for their completion.
public static Co WaitFor(IEnumerable<IEnumerator<Co>> tasks) {
return Scheduler.WaitFor(tasks.Select(ToTask).ToArray());
}
/// Runs tasks with specified parameters and waits for their completion.
public static Co WaitFor(IEnumerator<Co>[] tasks, TaskParameters tp) {
var ts = tasks.Select(ToTask).ToArray();
for (int i = 0; i < ts.Length; i++)
ts[i].Params = tp;
return Scheduler.WaitFor(ts);
}
/// Runs tasks with specified parameters and waits for their completion.
public static Co WaitFor(IEnumerable<IEnumerator<Co>> tasks, TaskParameters tp) {
var ts = tasks.Select(ToTask).ToArray();
for (int i = 0; i < ts.Length; i++)
ts[i].Params = tp;
return Scheduler.WaitFor(ts);
}
/// Runs tasks and waits for their completion.
public static Co WaitFor(IEnumerable<Task> tasks) {
return Scheduler.WaitFor(tasks.ToArray());
}
/// Runs tasks and waits for their completion.
public static Co WaitFor(Task[] tasks) {
return Scheduler.WaitFor(tasks);
}
/// Runs task and waits for its completion.
public static Co WaitFor(Task task) {
return Scheduler.WaitFor(task);
}
/// Runs task and waits for its completion.
public static Co Do(IEnumerator<Co> task) {
Scheduler.CurrentTask.Value.Push(task);
return Co.Continue;
}
/// Runs task with specified parameters and waits for its completion.
public static Co WaitFor(IEnumerator<Co> task, TaskParameters tp) {
return Scheduler.WaitFor(new Task(task, tp));
}
/// Runs task and waits for its completion.
public static Co Do(Action action) {
Scheduler.CurrentTask.Value.Push(action);
return Co.Continue;
}
/// Runs task with specified parameters and waits for its completion.
public static Co WaitFor(Action action, TaskParameters tp) {
return Scheduler.WaitFor(new Task(action, tp));
}
public static Co WaitFor<T>(T msg) where T : C.BindGen.IMessage {
return new Co {
Type = CoType.WaitForMessage,
Message = new C.CSMessage(msg.Handle),
};
}
public static void WaitForAnd<T>(T msg, Action cb) where T : C.BindGen.IMessage {
Scheduler.WaitForAnd(msg, new Task(cb));
}
}
public enum Type {
CPU,
IO,
}
public enum Priority {
Critical,
High,
Normal,
Low,
Background,
}
public struct TaskParameters {
public string Name;
public Type Type;
public Priority Priority;
public bool SameTypeAndPriority(TaskParameters rhs) {
return Type == rhs.Type && Priority == rhs.Priority;
}
public static readonly TaskParameters Default = new TaskParameters {
Name = "unknown",
Type = Type.CPU,
Priority = Priority.Normal,
};
public static TaskParameters Named(string name) {
var tp = Default;
tp.Name = name;
return tp;
}
}
public class Task {
public TaskParameters Params = TaskParameters.Default;
public Counter Counter;
public Mutex Mutex;
Stack<IEnumerator<Co>> stack = new Stack<IEnumerator<Co>>(4);
static IEnumerator<Co> ActionTask(Action action) {
action();
yield break;
}
public Task(Action action) {
stack.Push(ActionTask(action));
}
public Task(Action action, TaskParameters tp) {
stack.Push(ActionTask(action));
Params = tp;
}
public Task(IEnumerator<Co> task) {
stack.Push(task);
}
public Task(IEnumerator<Co> task, TaskParameters tp) {
stack.Push(task);
Params = tp;
}
public void Push(IEnumerator<Co> task) {
stack.Push(task);
}
public void Push(Action action) {
stack.Push(ActionTask(action));
}
public Co Run() {
while (stack.Count > 0) {
var enumerator = stack.Peek();
if (!enumerator.MoveNext()) {
enumerator.Dispose();
stack.Pop();
continue;
}
Co d = enumerator.Current;
if (d.Type == CoType.Done) {
enumerator.Dispose();
stack.Pop();
continue;
}
return d;
}
return Co.Done;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment