Skip to content

cemeyer/taskmn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Taskmn is an M:N userspace:kernel cooperative threading library built on top
of Russ Cox's libtask.

First of all: please DO NOT actually use this. It will bring you headache upon
headache, and is a poor solution to a problem that doesn't exist. This is
mostly just going on the internet for reference.

Much of the code is derived from libtask, which has various MIT- and BSD-
licensed bits.

Any significant changes I have made are released under the terms of the MIT
license. Do what you will with it (but again, seriously, don't use it).

Additionally: This was originally built to work on our hacked-up FreeBSD-
derived OS; I've quickly hacked it up so it at least compiles on Linux now
(althought we may have lost FreeBSD in the process, whatever). Expect
everything to be broken.

AGAIN: THIS IS STUPID, DON'T USE IT.

Thanks,
Conrad

=============================================================================

This is a very hacked-up libtask for M:N userspace threading. We've nuked the
print crap, the channels, 'system' tasks, and support for non-x86 architectures.

We have added the concept of a libtask context, to allow for multiple instances
per process. However, this shouldn't be necessary because libtaskmn manages a
threadpool. Instead of taskmain(), we have:

int     libtaskmn(void (*f)(Task *, void *arg), void *arg, int nthr);

This function is documented in taskmn.h.

libtaskmn will log to syslog at LOG_DEBUG level if you open a log for it and
set the environment variable TASKMN_SPAM. Its messages will be prefixed
"=lt=" (this was mostly for my use in debugging).

=======================================================================
The original README has also been hacked up. Here it is in its Shelley-
inspired glory:
=======================================================================

Libtaskmn is a threadpool library. It should compile and limp along on most x86
and amd64 Unixes (Linux included).

Libtaskmn gives the programmer the illusion of infinite (to the limits of
memory) threads, but these are actually running on a limited-size
threadpool. For clarity, we refer to the coroutines as "tasks," not
threads, but the programmer should keep in mind that they may run
concurrently.

Scheduling is somewhat cooperative. If the number of live tasks is greater
than the size of the threadpool, some tasks will be wait to run. Many
functions provided in taskmn.h can yield the thread to another task;
these should be documented below. Programs using taskmn should
#include <taskmn.h>.

--- Basic task manipulation

int taskcreate(Task *, void (*f)(Task*, void *arg), void *arg);

	Create a new task running f(arg); returns the task id.

void taskexit(Task *, int status);

	Exit the current task. If this is the last task, taskmn exits

int taskyield(Task *);
	
	Explicitly give up the CPU. The current task will be scheduled
	again once all the other currently-ready tasks have a chance
	to run. Returns the number of other tasks that ran while the
	current task was waiting. (Zero means there are no other tasks
	trying to run.)

int taskdelay(Task *, unsigned int ms)

	Explicitly give up the CPU for at least ms milliseconds. Other tasks
    continue to run during this time. Returns the number of milliseconds
    elapsed.

void** taskdata(Task *);

	Return a pointer to a single per-task void* pointer.
	You can use this as a per-task storage place.

void taskname(Task *, char*, ...);

	Sets the current task's name; uses sprintf under the covers. Max of
    256 characters.
	
char* taskgetname(Task *);

	Returns the current task's name. The buffer is owned by taskmn and
    should not be freed by the caller.
	
void taskstate(Task *, char*, ...);
char* taskgetstate(Task *);

	Like taskname and taskgetname but for the task state. Unlike taskname,
    taskstate is set by taskmn itself in many places, so keep that in
    mind.

unsigned int taskid(Task *);

	Return the unique task id for the current task.

void taskpoolsize(Task *, int);

    Sets the size of the task pool (number of threads).

--- Non-blocking I/O

There is a small amount of runtime support for non-blocking I/O
on file descriptors. Keep in mind that on unix, file I/O will block
regardless of O_NONBLOCK on the fd. Therefore, these are only really
useful for socket/pipe IO.

Tasks blocked on non-block IO will only resume when the set of live
tasks has quiesced such that at least one thread in the threadpool
is idle. (This behavior is inherited from libtask.)

int fdnoblock(int fd);

	Sets I/O on the given fd to be non-blocking. Returns -1 on error,
    setting errno. See fcntl(2), but I think the only error should be
    EBADF. Should be called before any of the following fd routines.

ssize_t fdread(Task *, int, void*, int);

	Like regular read(), but puts task to sleep on EAGAIN instead of
    blocking the whole program.

    fdread1() is similar, but puts the task to sleep first.

ssize_t fdwrite(Task *, int, void*, int);

	Like regular write(), but puts task to sleep on EAGAIN (i.e., the
    outgoing socket buffer or the pipe buffer is full).

void fdwait(Task *, int fd, char rw);

	Low-level call sitting underneath fdread and fdwrite.
	Puts task to sleep while waiting for I/O to be possible on fd.
	Rw specifies type of I/O: 'r' means read, 'w' means write,
	anything else means just exceptional conditions (hang up, etc.)
	The 'r' and 'w' also wake up for exceptional conditions.

--- Network I/O

These are convenient packaging of the ugly Unix socket routines.
They can all put the current task to sleep during the call.  

int netannounce(Task *, int proto, char *address, int port)

	Start a network listener running on address and port of protocol.
	Proto is either TCP or UDP. Port is a port number.  Address is a
	string version of a host name or IP address. If address is null or
    "*", then announce binds to the given port on all available
    interfaces. Returns an fd to use with netaccept.

    On error, returns -1, setting errno. taskstate() will show which
    step failed.

	Examples: netannounce(TCP, "localhost", 80) or 
		netannounce(TCP, "127.0.0.1", 80) or netannounce(TCP, 0, 80).

int netaccept(Task *, int fd, char *server, int *port)

	Get the next connection that comes in to the listener fd.
	Returns an fd to use to talk to the client who just connected.

    Server is filled with the remote IP and must be big enough
    to contain it; or, it can be null.

	Port is filled in with the remote port; or, it can be null.

    Returns an fd, or -1 on error. See accept(2) for sources of error.

	Example:
		char server[16];
		int port;
		
		if(netaccept(fd, server, &port) >= 0)
			printf("connect from %s:%d", server, port);

int netdial(Task *, int proto, char *name, int port)

	Create a new (outgoing) connection to a particular host.
	Name can be an ip address or a domain name.

    Returns an fd or -1 on error; see taskstate and errno for
    error source.

	Example: netdial(TCP, "www.google.com", 80)
		or netdial(TCP, "18.26.4.9", 80)

--- Time

unsigned taskdelay(Task *, unsigned ms)

	Put the current task to sleep for approximately ms milliseconds.
	Return the actual amount of time slept, in milliseconds.

--- Example programs

We have inherited some example programs from upstream libtask, but we've
changed the API somewhat and haven't verified that they're still
function. They may be educational anyway; see the demo/ directory.

--- Yielding condition variables ---

void rendezinit(Rendez *);

void tasksleep(Task *, Rendez *r);
int taskwakeup(Task *, Rendez *r);
int taskwakeupall(Task *, Rendez *r);

	A Rendez is a condition variable. You initialize it with rendezinit()
    but you don't need to do anything special to clean it up.

    tasksleep() blocks the running task on r until woken by taskwakeup()
    or taskwakeupall(). (It is the typical CV "wait" primitive.)

    taskwakeup() wakes the first task sleeping on r, if any ("signal" or
    "notify"). taskwakeupall() wakes all tasks sleeping on r, if any
    ("notifyall"). Both return the number of tasks woken.

About

DEADPROJECT M:N cooperative thread library built on libtask (DOES NOT WORK for many use cases, slow, don't use this, bitrotted, etc)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published