Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

libactor

libactor is a C library implementing the Actor model using pthreads.

The library works great, but one caveat is that if one actor crashes -- they all fall down. In a future release there will be sandboxing of each actor.

To install:

./configure
make
sudo make install

Try out the example:

gcc -lactor -o example examples/example.c && ./example

You may have to run ldconfig to reload the library cache.

Usage

To use libactor, include <libactor/actor.h> in your project and compile with the flag -lactor.

Declaring your Actors

Actors are just threads, and as in pthreads, a thread is an executing function. To define a new actor you can just define a new function that takes a single void* as an argument and returns a single void*:

void * foo(void * args) {
/* your Actor's logic goes here */
}

For clarity, you can use the macro ACTOR_FUNCTION(name, args), where name is the name of the function, and args is any arguments passed to the actor as a void*, like so:

ACTOR_FUNCTION(foo, args) {
/* your Actor's logic goes here */
}

libactor distinguishes a main actor. This actor will be executed when the application starts, and passed a pointer to a struct containing the program arguments. In your main file, declare your main actor like so:

ACTOR_FUNCTION(main_actor, args) {
struct actor_main * main = (struct actor_main *) args;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(int x = 0; x < main->argc; x++)
printf("Argument: %s\n", main->argv[x]);
}
DECLARE_ACTOR_MAIN(main_actor)

Managing your Actors

To spawn a new Actor, use spawn_actor(function, args). To spawn the foo Actor with a NULL pointer as an argument:

ACTOR_FUNCTION(main_actor, args) {
actor_id foo_id = spawn_actor(foo, NULL);
}

Notice the return type of spawn_actor(): an actor_id. This uniquely identifies the spawned Actor, and allows communication between Actors to identify the sender and receiver.

After a foo Actor is spawned, it can obtain its ID using actor_self():

ACTOR_FUNCTION(foo, args) {
actor_id my_id = actor_self();
}

Message-passing

Communication uses messages. All messages are of type actor_msg_t, and are created like this:

actor_send_msg(
foo, /* The Actor to send to */
PING_MSG, /* The message type */
NULL, /* A pointer to the message */
0 /* The length in bytes of the message */
);

The type should be greater than 100, as anything below that may be used by the library.

.. cfunction:: void actor_broadcast_msg(long type, void *data, size_t size)
Broadcasts a message to all actors.
.. cfunction:: void actor_reply_msg(actor_msg_t *a, long type, void *data, size_t size)
Reply to a received message.
.. cfunction:: actor_msg_t *actor_receive()
Receives a message from the actor's mailbox.
.. cfunction:: actor_msg_t *actor_receive_timeout(long timeout)
Same as :cfunc:`actor_receive`, but let's you specify a timeout (in milliseconds).

Memory Management

libactor uses pthreads for concurrency. If you allocate memory with :cfunc:`malloc` and pass a pointer or try to access the memory in a different actor, your application may crash. Therefore, if you plan to send a message to another actor, make sure that the message is complete(no pointers, only raw data). See :ref:`memory-example`.

libactor provides some convenience functions for managing memory. Please use these in your actors. Reference counting is used to manage memory. When an actor exits, any unfreed memory will be automatically freed. (But you should still release anything you are not using).

.. cfunction:: void *amalloc(size_t size)
Allocates a block of memory for an actor.
.. cfunction:: void arelease(void *block)
Call this function to release the memory. The reference count is decremented. When it reaches 0, the actual memory is freed.
.. cfunction:: void aretain(void *block)
Retains a block of memory. Use this to hold on to a block of memory. The reference count is incremented.

Example

This is okay:

struct user {
char *username;
char *password;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

This is bad:

struct usr_login_info {
char *username;
char *password;
};
struct user {
struct usr_login_info *info;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

In the bad example, the user struct will be copied, but the pointer to info may then be accessed by multiple actors.

Ping/Pong Actor Example

Below is a simple example of how to use the actor library. One actor will be spawned which will then spawn another actor, send it a ping message, and loop.

main.c:

#include <stdio.h>
#include <libactor/actor.h>
ACTOR_FUNCTION(pong_func, args) {
actor_msg_t *msg;
while(1) {
msg = actor_receive();
if(msg->type == PING_MSG) {
printf("PING! ");
actor_reply_msg(msg, PONG_MSG, NULL, 0);
}
arelease(msg);
}
}
ACTOR_FUNCTION(ping_func, args) {
actor_msg_t *msg;
actor_id aid = spawn_actor(pong_func, NULL);
while(1) {
actor_send_msg(aid, PING_MSG, NULL, 0);
msg = actor_receive();
if(msg->type == PONG_MSG) printf("PONG!\n");
arelease(msg);
sleep(5);
}
}
ACTOR_FUNCTION(main_func, args) {
struct actor_main *main = (struct actor_main*)args;
int x;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(x = 0; x < main->argc; x++) printf("Argument: %s\n", main->argv[x]);
/* PING/PONG example */
spawn_actor(ping_func, NULL);
}

About

Actor Model Library for C

Resources

Stars

55 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

libactor

libactor is a C library implementing the Actor model using pthreads.

The library works great, but one caveat is that if one actor crashes -- they all fall down. In a future release there will be sandboxing of each actor.

To install:

./configure
make
sudo make install

Try out the example:

gcc -lactor -o example examples/example.c && ./example

You may have to run ldconfig to reload the library cache.

Usage

To use libactor, include <libactor/actor.h> in your project and compile with the flag -lactor.

Declaring your Actors

Actors are just threads, and as in pthreads, a thread is an executing function. To define a new actor you can just define a new function that takes a single void* as an argument and returns a single void*:

void * foo(void * args) {
/* your Actor's logic goes here */
}

For clarity, you can use the macro ACTOR_FUNCTION(name, args), where name is the name of the function, and args is any arguments passed to the actor as a void*, like so:

ACTOR_FUNCTION(foo, args) {
/* your Actor's logic goes here */
}

libactor distinguishes a main actor. This actor will be executed when the application starts, and passed a pointer to a struct containing the program arguments. In your main file, declare your main actor like so:

ACTOR_FUNCTION(main_actor, args) {
struct actor_main * main = (struct actor_main *) args;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(int x = 0; x < main->argc; x++)
printf("Argument: %s\n", main->argv[x]);
}
DECLARE_ACTOR_MAIN(main_actor)

Managing your Actors

To spawn a new Actor, use spawn_actor(function, args). To spawn the foo Actor with a NULL pointer as an argument:

ACTOR_FUNCTION(main_actor, args) {
actor_id foo_id = spawn_actor(foo, NULL);
}

Notice the return type of spawn_actor(): an actor_id. This uniquely identifies the spawned Actor, and allows communication between Actors to identify the sender and receiver.

After a foo Actor is spawned, it can obtain its ID using actor_self():

ACTOR_FUNCTION(foo, args) {
actor_id my_id = actor_self();
}

Message-passing

Communication uses messages. All messages are of type actor_msg_t, and are created like this:

actor_send_msg(
foo, /* The Actor to send to */
PING_MSG, /* The message type */
NULL, /* A pointer to the message */
0 /* The length in bytes of the message */
);

The type should be greater than 100, as anything below that may be used by the library.

.. cfunction:: void actor_broadcast_msg(long type, void *data, size_t size)
Broadcasts a message to all actors.
.. cfunction:: void actor_reply_msg(actor_msg_t *a, long type, void *data, size_t size)
Reply to a received message.
.. cfunction:: actor_msg_t *actor_receive()
Receives a message from the actor's mailbox.
.. cfunction:: actor_msg_t *actor_receive_timeout(long timeout)
Same as :cfunc:`actor_receive`, but let's you specify a timeout (in milliseconds).

Memory Management

libactor uses pthreads for concurrency. If you allocate memory with :cfunc:`malloc` and pass a pointer or try to access the memory in a different actor, your application may crash. Therefore, if you plan to send a message to another actor, make sure that the message is complete(no pointers, only raw data). See :ref:`memory-example`.

libactor provides some convenience functions for managing memory. Please use these in your actors. Reference counting is used to manage memory. When an actor exits, any unfreed memory will be automatically freed. (But you should still release anything you are not using).

.. cfunction:: void *amalloc(size_t size)
Allocates a block of memory for an actor.
.. cfunction:: void arelease(void *block)
Call this function to release the memory. The reference count is decremented. When it reaches 0, the actual memory is freed.
.. cfunction:: void aretain(void *block)
Retains a block of memory. Use this to hold on to a block of memory. The reference count is incremented.

Example

This is okay:

struct user {
char *username;
char *password;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

This is bad:

struct usr_login_info {
char *username;
char *password;
};
struct user {
struct usr_login_info *info;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

In the bad example, the user struct will be copied, but the pointer to info may then be accessed by multiple actors.

Ping/Pong Actor Example

Below is a simple example of how to use the actor library. One actor will be spawned which will then spawn another actor, send it a ping message, and loop.

main.c:

#include <stdio.h>
#include <libactor/actor.h>
ACTOR_FUNCTION(pong_func, args) {
actor_msg_t *msg;
while(1) {
msg = actor_receive();
if(msg->type == PING_MSG) {
printf("PING! ");
actor_reply_msg(msg, PONG_MSG, NULL, 0);
}
arelease(msg);
}
}
ACTOR_FUNCTION(ping_func, args) {
actor_msg_t *msg;
actor_id aid = spawn_actor(pong_func, NULL);
while(1) {
actor_send_msg(aid, PING_MSG, NULL, 0);
msg = actor_receive();
if(msg->type == PONG_MSG) printf("PONG!\n");
arelease(msg);
sleep(5);
}
}
ACTOR_FUNCTION(main_func, args) {
struct actor_main *main = (struct actor_main*)args;
int x;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(x = 0; x < main->argc; x++) printf("Argument: %s\n", main->argv[x]);
/* PING/PONG example */
spawn_actor(ping_func, NULL);
}

About

Actor Model Library for C

Resources

Stars

55 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

libactor

libactor is a C library implementing the Actor model using pthreads.

The library works great, but one caveat is that if one actor crashes -- they all fall down. In a future release there will be sandboxing of each actor.

To install:

./configure
make
sudo make install

Try out the example:

gcc -lactor -o example examples/example.c && ./example

You may have to run ldconfig to reload the library cache.

Usage

To use libactor, include <libactor/actor.h> in your project and compile with the flag -lactor.

Declaring your Actors

Actors are just threads, and as in pthreads, a thread is an executing function. To define a new actor you can just define a new function that takes a single void* as an argument and returns a single void*:

void * foo(void * args) {
/* your Actor's logic goes here */
}

For clarity, you can use the macro ACTOR_FUNCTION(name, args), where name is the name of the function, and args is any arguments passed to the actor as a void*, like so:

ACTOR_FUNCTION(foo, args) {
/* your Actor's logic goes here */
}

libactor distinguishes a main actor. This actor will be executed when the application starts, and passed a pointer to a struct containing the program arguments. In your main file, declare your main actor like so:

ACTOR_FUNCTION(main_actor, args) {
struct actor_main * main = (struct actor_main *) args;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(int x = 0; x < main->argc; x++)
printf("Argument: %s\n", main->argv[x]);
}
DECLARE_ACTOR_MAIN(main_actor)

Managing your Actors

To spawn a new Actor, use spawn_actor(function, args). To spawn the foo Actor with a NULL pointer as an argument:

ACTOR_FUNCTION(main_actor, args) {
actor_id foo_id = spawn_actor(foo, NULL);
}

Notice the return type of spawn_actor(): an actor_id. This uniquely identifies the spawned Actor, and allows communication between Actors to identify the sender and receiver.

After a foo Actor is spawned, it can obtain its ID using actor_self():

ACTOR_FUNCTION(foo, args) {
actor_id my_id = actor_self();
}

Message-passing

Communication uses messages. All messages are of type actor_msg_t, and are created like this:

actor_send_msg(
foo, /* The Actor to send to */
PING_MSG, /* The message type */
NULL, /* A pointer to the message */
0 /* The length in bytes of the message */
);

The type should be greater than 100, as anything below that may be used by the library.

.. cfunction:: void actor_broadcast_msg(long type, void *data, size_t size)
Broadcasts a message to all actors.
.. cfunction:: void actor_reply_msg(actor_msg_t *a, long type, void *data, size_t size)
Reply to a received message.
.. cfunction:: actor_msg_t *actor_receive()
Receives a message from the actor's mailbox.
.. cfunction:: actor_msg_t *actor_receive_timeout(long timeout)
Same as :cfunc:`actor_receive`, but let's you specify a timeout (in milliseconds).

Memory Management

libactor uses pthreads for concurrency. If you allocate memory with :cfunc:`malloc` and pass a pointer or try to access the memory in a different actor, your application may crash. Therefore, if you plan to send a message to another actor, make sure that the message is complete(no pointers, only raw data). See :ref:`memory-example`.

libactor provides some convenience functions for managing memory. Please use these in your actors. Reference counting is used to manage memory. When an actor exits, any unfreed memory will be automatically freed. (But you should still release anything you are not using).

.. cfunction:: void *amalloc(size_t size)
Allocates a block of memory for an actor.
.. cfunction:: void arelease(void *block)
Call this function to release the memory. The reference count is decremented. When it reaches 0, the actual memory is freed.
.. cfunction:: void aretain(void *block)
Retains a block of memory. Use this to hold on to a block of memory. The reference count is incremented.

Example

This is okay:

struct user {
char *username;
char *password;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

This is bad:

struct usr_login_info {
char *username;
char *password;
};
struct user {
struct usr_login_info *info;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

In the bad example, the user struct will be copied, but the pointer to info may then be accessed by multiple actors.

Ping/Pong Actor Example

Below is a simple example of how to use the actor library. One actor will be spawned which will then spawn another actor, send it a ping message, and loop.

main.c:

#include <stdio.h>
#include <libactor/actor.h>
ACTOR_FUNCTION(pong_func, args) {
actor_msg_t *msg;
while(1) {
msg = actor_receive();
if(msg->type == PING_MSG) {
printf("PING! ");
actor_reply_msg(msg, PONG_MSG, NULL, 0);
}
arelease(msg);
}
}
ACTOR_FUNCTION(ping_func, args) {
actor_msg_t *msg;
actor_id aid = spawn_actor(pong_func, NULL);
while(1) {
actor_send_msg(aid, PING_MSG, NULL, 0);
msg = actor_receive();
if(msg->type == PONG_MSG) printf("PONG!\n");
arelease(msg);
sleep(5);
}
}
ACTOR_FUNCTION(main_func, args) {
struct actor_main *main = (struct actor_main*)args;
int x;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(x = 0; x < main->argc; x++) printf("Argument: %s\n", main->argv[x]);
/* PING/PONG example */
spawn_actor(ping_func, NULL);
}

About

Actor Model Library for C

Resources

Stars

55 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

libactor

libactor is a C library implementing the Actor model using pthreads.

The library works great, but one caveat is that if one actor crashes -- they all fall down. In a future release there will be sandboxing of each actor.

To install:

./configure
make
sudo make install

Try out the example:

gcc -lactor -o example examples/example.c && ./example

You may have to run ldconfig to reload the library cache.

Usage

To use libactor, include <libactor/actor.h> in your project and compile with the flag -lactor.

Declaring your Actors

Actors are just threads, and as in pthreads, a thread is an executing function. To define a new actor you can just define a new function that takes a single void* as an argument and returns a single void*:

void * foo(void * args) {
/* your Actor's logic goes here */
}

For clarity, you can use the macro ACTOR_FUNCTION(name, args), where name is the name of the function, and args is any arguments passed to the actor as a void*, like so:

ACTOR_FUNCTION(foo, args) {
/* your Actor's logic goes here */
}

libactor distinguishes a main actor. This actor will be executed when the application starts, and passed a pointer to a struct containing the program arguments. In your main file, declare your main actor like so:

ACTOR_FUNCTION(main_actor, args) {
struct actor_main * main = (struct actor_main *) args;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(int x = 0; x < main->argc; x++)
printf("Argument: %s\n", main->argv[x]);
}
DECLARE_ACTOR_MAIN(main_actor)

Managing your Actors

To spawn a new Actor, use spawn_actor(function, args). To spawn the foo Actor with a NULL pointer as an argument:

ACTOR_FUNCTION(main_actor, args) {
actor_id foo_id = spawn_actor(foo, NULL);
}

Notice the return type of spawn_actor(): an actor_id. This uniquely identifies the spawned Actor, and allows communication between Actors to identify the sender and receiver.

After a foo Actor is spawned, it can obtain its ID using actor_self():

ACTOR_FUNCTION(foo, args) {
actor_id my_id = actor_self();
}

Message-passing

Communication uses messages. All messages are of type actor_msg_t, and are created like this:

actor_send_msg(
foo, /* The Actor to send to */
PING_MSG, /* The message type */
NULL, /* A pointer to the message */
0 /* The length in bytes of the message */
);

The type should be greater than 100, as anything below that may be used by the library.

.. cfunction:: void actor_broadcast_msg(long type, void *data, size_t size)
Broadcasts a message to all actors.
.. cfunction:: void actor_reply_msg(actor_msg_t *a, long type, void *data, size_t size)
Reply to a received message.
.. cfunction:: actor_msg_t *actor_receive()
Receives a message from the actor's mailbox.
.. cfunction:: actor_msg_t *actor_receive_timeout(long timeout)
Same as :cfunc:`actor_receive`, but let's you specify a timeout (in milliseconds).

Memory Management

libactor uses pthreads for concurrency. If you allocate memory with :cfunc:`malloc` and pass a pointer or try to access the memory in a different actor, your application may crash. Therefore, if you plan to send a message to another actor, make sure that the message is complete(no pointers, only raw data). See :ref:`memory-example`.

libactor provides some convenience functions for managing memory. Please use these in your actors. Reference counting is used to manage memory. When an actor exits, any unfreed memory will be automatically freed. (But you should still release anything you are not using).

.. cfunction:: void *amalloc(size_t size)
Allocates a block of memory for an actor.
.. cfunction:: void arelease(void *block)
Call this function to release the memory. The reference count is decremented. When it reaches 0, the actual memory is freed.
.. cfunction:: void aretain(void *block)
Retains a block of memory. Use this to hold on to a block of memory. The reference count is incremented.

Example

This is okay:

struct user {
char *username;
char *password;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

This is bad:

struct usr_login_info {
char *username;
char *password;
};
struct user {
struct usr_login_info *info;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

In the bad example, the user struct will be copied, but the pointer to info may then be accessed by multiple actors.

Ping/Pong Actor Example

Below is a simple example of how to use the actor library. One actor will be spawned which will then spawn another actor, send it a ping message, and loop.

main.c:

#include <stdio.h>
#include <libactor/actor.h>
ACTOR_FUNCTION(pong_func, args) {
actor_msg_t *msg;
while(1) {
msg = actor_receive();
if(msg->type == PING_MSG) {
printf("PING! ");
actor_reply_msg(msg, PONG_MSG, NULL, 0);
}
arelease(msg);
}
}
ACTOR_FUNCTION(ping_func, args) {
actor_msg_t *msg;
actor_id aid = spawn_actor(pong_func, NULL);
while(1) {
actor_send_msg(aid, PING_MSG, NULL, 0);
msg = actor_receive();
if(msg->type == PONG_MSG) printf("PONG!\n");
arelease(msg);
sleep(5);
}
}
ACTOR_FUNCTION(main_func, args) {
struct actor_main *main = (struct actor_main*)args;
int x;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(x = 0; x < main->argc; x++) printf("Argument: %s\n", main->argv[x]);
/* PING/PONG example */
spawn_actor(ping_func, NULL);
}

About

Actor Model Library for C

Resources

Stars

55 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

libactor

libactor is a C library implementing the Actor model using pthreads.

The library works great, but one caveat is that if one actor crashes -- they all fall down. In a future release there will be sandboxing of each actor.

To install:

./configure
make
sudo make install

Try out the example:

gcc -lactor -o example examples/example.c && ./example

You may have to run ldconfig to reload the library cache.

Usage

To use libactor, include <libactor/actor.h> in your project and compile with the flag -lactor.

Declaring your Actors

Actors are just threads, and as in pthreads, a thread is an executing function. To define a new actor you can just define a new function that takes a single void* as an argument and returns a single void*:

void * foo(void * args) {
/* your Actor's logic goes here */
}

For clarity, you can use the macro ACTOR_FUNCTION(name, args), where name is the name of the function, and args is any arguments passed to the actor as a void*, like so:

ACTOR_FUNCTION(foo, args) {
/* your Actor's logic goes here */
}

libactor distinguishes a main actor. This actor will be executed when the application starts, and passed a pointer to a struct containing the program arguments. In your main file, declare your main actor like so:

ACTOR_FUNCTION(main_actor, args) {
struct actor_main * main = (struct actor_main *) args;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(int x = 0; x < main->argc; x++)
printf("Argument: %s\n", main->argv[x]);
}
DECLARE_ACTOR_MAIN(main_actor)

Managing your Actors

To spawn a new Actor, use spawn_actor(function, args). To spawn the foo Actor with a NULL pointer as an argument:

ACTOR_FUNCTION(main_actor, args) {
actor_id foo_id = spawn_actor(foo, NULL);
}

Notice the return type of spawn_actor(): an actor_id. This uniquely identifies the spawned Actor, and allows communication between Actors to identify the sender and receiver.

After a foo Actor is spawned, it can obtain its ID using actor_self():

ACTOR_FUNCTION(foo, args) {
actor_id my_id = actor_self();
}

Message-passing

Communication uses messages. All messages are of type actor_msg_t, and are created like this:

actor_send_msg(
foo, /* The Actor to send to */
PING_MSG, /* The message type */
NULL, /* A pointer to the message */
0 /* The length in bytes of the message */
);

The type should be greater than 100, as anything below that may be used by the library.

.. cfunction:: void actor_broadcast_msg(long type, void *data, size_t size)
Broadcasts a message to all actors.
.. cfunction:: void actor_reply_msg(actor_msg_t *a, long type, void *data, size_t size)
Reply to a received message.
.. cfunction:: actor_msg_t *actor_receive()
Receives a message from the actor's mailbox.
.. cfunction:: actor_msg_t *actor_receive_timeout(long timeout)
Same as :cfunc:`actor_receive`, but let's you specify a timeout (in milliseconds).

Memory Management

libactor uses pthreads for concurrency. If you allocate memory with :cfunc:`malloc` and pass a pointer or try to access the memory in a different actor, your application may crash. Therefore, if you plan to send a message to another actor, make sure that the message is complete(no pointers, only raw data). See :ref:`memory-example`.

libactor provides some convenience functions for managing memory. Please use these in your actors. Reference counting is used to manage memory. When an actor exits, any unfreed memory will be automatically freed. (But you should still release anything you are not using).

.. cfunction:: void *amalloc(size_t size)
Allocates a block of memory for an actor.
.. cfunction:: void arelease(void *block)
Call this function to release the memory. The reference count is decremented. When it reaches 0, the actual memory is freed.
.. cfunction:: void aretain(void *block)
Retains a block of memory. Use this to hold on to a block of memory. The reference count is incremented.

Example

This is okay:

struct user {
char *username;
char *password;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

This is bad:

struct usr_login_info {
char *username;
char *password;
};
struct user {
struct usr_login_info *info;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

In the bad example, the user struct will be copied, but the pointer to info may then be accessed by multiple actors.

Ping/Pong Actor Example

Below is a simple example of how to use the actor library. One actor will be spawned which will then spawn another actor, send it a ping message, and loop.

main.c:

#include <stdio.h>
#include <libactor/actor.h>
ACTOR_FUNCTION(pong_func, args) {
actor_msg_t *msg;
while(1) {
msg = actor_receive();
if(msg->type == PING_MSG) {
printf("PING! ");
actor_reply_msg(msg, PONG_MSG, NULL, 0);
}
arelease(msg);
}
}
ACTOR_FUNCTION(ping_func, args) {
actor_msg_t *msg;
actor_id aid = spawn_actor(pong_func, NULL);
while(1) {
actor_send_msg(aid, PING_MSG, NULL, 0);
msg = actor_receive();
if(msg->type == PONG_MSG) printf("PONG!\n");
arelease(msg);
sleep(5);
}
}
ACTOR_FUNCTION(main_func, args) {
struct actor_main *main = (struct actor_main*)args;
int x;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(x = 0; x < main->argc; x++) printf("Argument: %s\n", main->argv[x]);
/* PING/PONG example */
spawn_actor(ping_func, NULL);
}

About

Actor Model Library for C

Resources

Stars

55 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

libactor

libactor is a C library implementing the Actor model using pthreads.

The library works great, but one caveat is that if one actor crashes -- they all fall down. In a future release there will be sandboxing of each actor.

To install:

./configure
make
sudo make install

Try out the example:

gcc -lactor -o example examples/example.c && ./example

You may have to run ldconfig to reload the library cache.

Usage

To use libactor, include <libactor/actor.h> in your project and compile with the flag -lactor.

Declaring your Actors

Actors are just threads, and as in pthreads, a thread is an executing function. To define a new actor you can just define a new function that takes a single void* as an argument and returns a single void*:

void * foo(void * args) {
/* your Actor's logic goes here */
}

For clarity, you can use the macro ACTOR_FUNCTION(name, args), where name is the name of the function, and args is any arguments passed to the actor as a void*, like so:

ACTOR_FUNCTION(foo, args) {
/* your Actor's logic goes here */
}

libactor distinguishes a main actor. This actor will be executed when the application starts, and passed a pointer to a struct containing the program arguments. In your main file, declare your main actor like so:

ACTOR_FUNCTION(main_actor, args) {
struct actor_main * main = (struct actor_main *) args;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(int x = 0; x < main->argc; x++)
printf("Argument: %s\n", main->argv[x]);
}
DECLARE_ACTOR_MAIN(main_actor)

Managing your Actors

To spawn a new Actor, use spawn_actor(function, args). To spawn the foo Actor with a NULL pointer as an argument:

ACTOR_FUNCTION(main_actor, args) {
actor_id foo_id = spawn_actor(foo, NULL);
}

Notice the return type of spawn_actor(): an actor_id. This uniquely identifies the spawned Actor, and allows communication between Actors to identify the sender and receiver.

After a foo Actor is spawned, it can obtain its ID using actor_self():

ACTOR_FUNCTION(foo, args) {
actor_id my_id = actor_self();
}

Message-passing

Communication uses messages. All messages are of type actor_msg_t, and are created like this:

actor_send_msg(
foo, /* The Actor to send to */
PING_MSG, /* The message type */
NULL, /* A pointer to the message */
0 /* The length in bytes of the message */
);

The type should be greater than 100, as anything below that may be used by the library.

.. cfunction:: void actor_broadcast_msg(long type, void *data, size_t size)
Broadcasts a message to all actors.
.. cfunction:: void actor_reply_msg(actor_msg_t *a, long type, void *data, size_t size)
Reply to a received message.
.. cfunction:: actor_msg_t *actor_receive()
Receives a message from the actor's mailbox.
.. cfunction:: actor_msg_t *actor_receive_timeout(long timeout)
Same as :cfunc:`actor_receive`, but let's you specify a timeout (in milliseconds).

Memory Management

libactor uses pthreads for concurrency. If you allocate memory with :cfunc:`malloc` and pass a pointer or try to access the memory in a different actor, your application may crash. Therefore, if you plan to send a message to another actor, make sure that the message is complete(no pointers, only raw data). See :ref:`memory-example`.

libactor provides some convenience functions for managing memory. Please use these in your actors. Reference counting is used to manage memory. When an actor exits, any unfreed memory will be automatically freed. (But you should still release anything you are not using).

.. cfunction:: void *amalloc(size_t size)
Allocates a block of memory for an actor.
.. cfunction:: void arelease(void *block)
Call this function to release the memory. The reference count is decremented. When it reaches 0, the actual memory is freed.
.. cfunction:: void aretain(void *block)
Retains a block of memory. Use this to hold on to a block of memory. The reference count is incremented.

Example

This is okay:

struct user {
char *username;
char *password;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

This is bad:

struct usr_login_info {
char *username;
char *password;
};
struct user {
struct usr_login_info *info;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

In the bad example, the user struct will be copied, but the pointer to info may then be accessed by multiple actors.

Ping/Pong Actor Example

Below is a simple example of how to use the actor library. One actor will be spawned which will then spawn another actor, send it a ping message, and loop.

main.c:

#include <stdio.h>
#include <libactor/actor.h>
ACTOR_FUNCTION(pong_func, args) {
actor_msg_t *msg;
while(1) {
msg = actor_receive();
if(msg->type == PING_MSG) {
printf("PING! ");
actor_reply_msg(msg, PONG_MSG, NULL, 0);
}
arelease(msg);
}
}
ACTOR_FUNCTION(ping_func, args) {
actor_msg_t *msg;
actor_id aid = spawn_actor(pong_func, NULL);
while(1) {
actor_send_msg(aid, PING_MSG, NULL, 0);
msg = actor_receive();
if(msg->type == PONG_MSG) printf("PONG!\n");
arelease(msg);
sleep(5);
}
}
ACTOR_FUNCTION(main_func, args) {
struct actor_main *main = (struct actor_main*)args;
int x;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(x = 0; x < main->argc; x++) printf("Argument: %s\n", main->argv[x]);
/* PING/PONG example */
spawn_actor(ping_func, NULL);
}

About

Actor Model Library for C

Resources

Stars

55 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

libactor

libactor is a C library implementing the Actor model using pthreads.

The library works great, but one caveat is that if one actor crashes -- they all fall down. In a future release there will be sandboxing of each actor.

To install:

./configure
make
sudo make install

Try out the example:

gcc -lactor -o example examples/example.c && ./example

You may have to run ldconfig to reload the library cache.

Usage

To use libactor, include <libactor/actor.h> in your project and compile with the flag -lactor.

Declaring your Actors

Actors are just threads, and as in pthreads, a thread is an executing function. To define a new actor you can just define a new function that takes a single void* as an argument and returns a single void*:

void * foo(void * args) {
/* your Actor's logic goes here */
}

For clarity, you can use the macro ACTOR_FUNCTION(name, args), where name is the name of the function, and args is any arguments passed to the actor as a void*, like so:

ACTOR_FUNCTION(foo, args) {
/* your Actor's logic goes here */
}

libactor distinguishes a main actor. This actor will be executed when the application starts, and passed a pointer to a struct containing the program arguments. In your main file, declare your main actor like so:

ACTOR_FUNCTION(main_actor, args) {
struct actor_main * main = (struct actor_main *) args;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(int x = 0; x < main->argc; x++)
printf("Argument: %s\n", main->argv[x]);
}
DECLARE_ACTOR_MAIN(main_actor)

Managing your Actors

To spawn a new Actor, use spawn_actor(function, args). To spawn the foo Actor with a NULL pointer as an argument:

ACTOR_FUNCTION(main_actor, args) {
actor_id foo_id = spawn_actor(foo, NULL);
}

Notice the return type of spawn_actor(): an actor_id. This uniquely identifies the spawned Actor, and allows communication between Actors to identify the sender and receiver.

After a foo Actor is spawned, it can obtain its ID using actor_self():

ACTOR_FUNCTION(foo, args) {
actor_id my_id = actor_self();
}

Message-passing

Communication uses messages. All messages are of type actor_msg_t, and are created like this:

actor_send_msg(
foo, /* The Actor to send to */
PING_MSG, /* The message type */
NULL, /* A pointer to the message */
0 /* The length in bytes of the message */
);

The type should be greater than 100, as anything below that may be used by the library.

.. cfunction:: void actor_broadcast_msg(long type, void *data, size_t size)
Broadcasts a message to all actors.
.. cfunction:: void actor_reply_msg(actor_msg_t *a, long type, void *data, size_t size)
Reply to a received message.
.. cfunction:: actor_msg_t *actor_receive()
Receives a message from the actor's mailbox.
.. cfunction:: actor_msg_t *actor_receive_timeout(long timeout)
Same as :cfunc:`actor_receive`, but let's you specify a timeout (in milliseconds).

Memory Management

libactor uses pthreads for concurrency. If you allocate memory with :cfunc:`malloc` and pass a pointer or try to access the memory in a different actor, your application may crash. Therefore, if you plan to send a message to another actor, make sure that the message is complete(no pointers, only raw data). See :ref:`memory-example`.

libactor provides some convenience functions for managing memory. Please use these in your actors. Reference counting is used to manage memory. When an actor exits, any unfreed memory will be automatically freed. (But you should still release anything you are not using).

.. cfunction:: void *amalloc(size_t size)
Allocates a block of memory for an actor.
.. cfunction:: void arelease(void *block)
Call this function to release the memory. The reference count is decremented. When it reaches 0, the actual memory is freed.
.. cfunction:: void aretain(void *block)
Retains a block of memory. Use this to hold on to a block of memory. The reference count is incremented.

Example

This is okay:

struct user {
char *username;
char *password;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

This is bad:

struct usr_login_info {
char *username;
char *password;
};
struct user {
struct usr_login_info *info;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

In the bad example, the user struct will be copied, but the pointer to info may then be accessed by multiple actors.

Ping/Pong Actor Example

Below is a simple example of how to use the actor library. One actor will be spawned which will then spawn another actor, send it a ping message, and loop.

main.c:

#include <stdio.h>
#include <libactor/actor.h>
ACTOR_FUNCTION(pong_func, args) {
actor_msg_t *msg;
while(1) {
msg = actor_receive();
if(msg->type == PING_MSG) {
printf("PING! ");
actor_reply_msg(msg, PONG_MSG, NULL, 0);
}
arelease(msg);
}
}
ACTOR_FUNCTION(ping_func, args) {
actor_msg_t *msg;
actor_id aid = spawn_actor(pong_func, NULL);
while(1) {
actor_send_msg(aid, PING_MSG, NULL, 0);
msg = actor_receive();
if(msg->type == PONG_MSG) printf("PONG!\n");
arelease(msg);
sleep(5);
}
}
ACTOR_FUNCTION(main_func, args) {
struct actor_main *main = (struct actor_main*)args;
int x;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(x = 0; x < main->argc; x++) printf("Argument: %s\n", main->argv[x]);
/* PING/PONG example */
spawn_actor(ping_func, NULL);
}

About

Actor Model Library for C

Resources

Stars

55 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

libactor

libactor is a C library implementing the Actor model using pthreads.

The library works great, but one caveat is that if one actor crashes -- they all fall down. In a future release there will be sandboxing of each actor.

To install:

./configure
make
sudo make install

Try out the example:

gcc -lactor -o example examples/example.c && ./example

You may have to run ldconfig to reload the library cache.

Usage

To use libactor, include <libactor/actor.h> in your project and compile with the flag -lactor.

Declaring your Actors

Actors are just threads, and as in pthreads, a thread is an executing function. To define a new actor you can just define a new function that takes a single void* as an argument and returns a single void*:

void * foo(void * args) {
/* your Actor's logic goes here */
}

For clarity, you can use the macro ACTOR_FUNCTION(name, args), where name is the name of the function, and args is any arguments passed to the actor as a void*, like so:

ACTOR_FUNCTION(foo, args) {
/* your Actor's logic goes here */
}

libactor distinguishes a main actor. This actor will be executed when the application starts, and passed a pointer to a struct containing the program arguments. In your main file, declare your main actor like so:

ACTOR_FUNCTION(main_actor, args) {
struct actor_main * main = (struct actor_main *) args;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(int x = 0; x < main->argc; x++)
printf("Argument: %s\n", main->argv[x]);
}
DECLARE_ACTOR_MAIN(main_actor)

Managing your Actors

To spawn a new Actor, use spawn_actor(function, args). To spawn the foo Actor with a NULL pointer as an argument:

ACTOR_FUNCTION(main_actor, args) {
actor_id foo_id = spawn_actor(foo, NULL);
}

Notice the return type of spawn_actor(): an actor_id. This uniquely identifies the spawned Actor, and allows communication between Actors to identify the sender and receiver.

After a foo Actor is spawned, it can obtain its ID using actor_self():

ACTOR_FUNCTION(foo, args) {
actor_id my_id = actor_self();
}

Message-passing

Communication uses messages. All messages are of type actor_msg_t, and are created like this:

actor_send_msg(
foo, /* The Actor to send to */
PING_MSG, /* The message type */
NULL, /* A pointer to the message */
0 /* The length in bytes of the message */
);

The type should be greater than 100, as anything below that may be used by the library.

.. cfunction:: void actor_broadcast_msg(long type, void *data, size_t size)
Broadcasts a message to all actors.
.. cfunction:: void actor_reply_msg(actor_msg_t *a, long type, void *data, size_t size)
Reply to a received message.
.. cfunction:: actor_msg_t *actor_receive()
Receives a message from the actor's mailbox.
.. cfunction:: actor_msg_t *actor_receive_timeout(long timeout)
Same as :cfunc:`actor_receive`, but let's you specify a timeout (in milliseconds).

Memory Management

libactor uses pthreads for concurrency. If you allocate memory with :cfunc:`malloc` and pass a pointer or try to access the memory in a different actor, your application may crash. Therefore, if you plan to send a message to another actor, make sure that the message is complete(no pointers, only raw data). See :ref:`memory-example`.

libactor provides some convenience functions for managing memory. Please use these in your actors. Reference counting is used to manage memory. When an actor exits, any unfreed memory will be automatically freed. (But you should still release anything you are not using).

.. cfunction:: void *amalloc(size_t size)
Allocates a block of memory for an actor.
.. cfunction:: void arelease(void *block)
Call this function to release the memory. The reference count is decremented. When it reaches 0, the actual memory is freed.
.. cfunction:: void aretain(void *block)
Retains a block of memory. Use this to hold on to a block of memory. The reference count is incremented.

Example

This is okay:

struct user {
char *username;
char *password;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

This is bad:

struct usr_login_info {
char *username;
char *password;
};
struct user {
struct usr_login_info *info;
int status;
};
struct user usermsg;
// initialize usermsg here
actor_send_msg(5, 1, &usermsg, sizeof(struct user));

In the bad example, the user struct will be copied, but the pointer to info may then be accessed by multiple actors.

Ping/Pong Actor Example

Below is a simple example of how to use the actor library. One actor will be spawned which will then spawn another actor, send it a ping message, and loop.

main.c:

#include <stdio.h>
#include <libactor/actor.h>
ACTOR_FUNCTION(pong_func, args) {
actor_msg_t *msg;
while(1) {
msg = actor_receive();
if(msg->type == PING_MSG) {
printf("PING! ");
actor_reply_msg(msg, PONG_MSG, NULL, 0);
}
arelease(msg);
}
}
ACTOR_FUNCTION(ping_func, args) {
actor_msg_t *msg;
actor_id aid = spawn_actor(pong_func, NULL);
while(1) {
actor_send_msg(aid, PING_MSG, NULL, 0);
msg = actor_receive();
if(msg->type == PONG_MSG) printf("PONG!\n");
arelease(msg);
sleep(5);
}
}
ACTOR_FUNCTION(main_func, args) {
struct actor_main *main = (struct actor_main*)args;
int x;
/* Accessing the arguments passed to the application */
printf("Number of arguments: %d\n", main->argc);
for(x = 0; x < main->argc; x++) printf("Argument: %s\n", main->argv[x]);
/* PING/PONG example */
spawn_actor(ping_func, NULL);
}

About

Actor Model Library for C

Resources

Stars

55 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages