Skip to content

Instantly share code, notes, and snippets.

@Zoxc
Created June 9, 2010 14:49
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 Zoxc/431580 to your computer and use it in GitHub Desktop.
Save Zoxc/431580 to your computer and use it in GitHub Desktop.
#include <stdbool.h>
/*
* Dummy typedefs for types used.
*/
typedef int event_t;
typedef int message_t;
/*
* Prototype for event functions.
*/
void event_clear(event_t event);
void event_set(event_t event);
void event_wait(event_t event);
/*
* A function that ensures compiler and hardware read/write order, also known as a memory barrier.
*/
inline void memory_barrier()
{
__sync_synchronize();
}
/*
* Portal is an implementation of a pipe where two threads can safely write and read from. It does not support multiple writers or readers.
*/
/*
* Part is a structure belonging to one of the threads.
*/
struct part {
/*
* The number of writes the other part has done.
*/
size_t write_count;
/*
* The number of reads this part has done.
*/
size_t read_count;
/*
* An event which if preset will be used to signal new messages.
*/
event_t event;
/*
* An event which if preset will be used to signal a reply to a synchronious message.
*/
event_t msg_event;
/*
* The id of the send synchronious message.
*/
size_t msg_id;
/*
* A buffer containg messages to be read.
*/
message_t buffer[];
};
struct portal {
/*
* The part belonging to the other thread.
*/
struct part *remote;
/*
* The part belonging to the local thread.
*/
struct part *local;
/*
* Event used for synchronizing.
*/
event_t event;
};
/*
* part_write()
* Write a message to a part.
*/
void part_write(struct part *part, message_t msg)
{
part->buffer[part->write_count] = msg;
memory_barrier();
part->write_count++;
memory_barrier();
}
/*
* part_read()
* Read a message from a part.
*/
message_t part_read(struct part *part)
{
message_t msg = part->buffer[part->read_count];
memory_barrier();
part->read_count++;
return msg;
}
/*
* part_pending()
* Check if there is pending messages in the part.
*/
message_t part_pending_msgs(struct part *part)
{
return part->read_count == part->write_count;
}
void portal_write(struct portal *portal, message_t msg)
{
part_write(portal->remote, msg);
}
void portal_write_and_notify(struct portal *portal, message_t msg)
{
part_write(portal->remote, msg);
/*
* Check if there is a pending waiting event, if so, trigger it.
*/
event_t event = portal->remote->event;
if(event)
event_set(event);
}
void portal_notify(struct portal *portal)
{
/*
* Check if there is a pending waiting event and waiting messages, if so, trigger it.
*/
event_t event = portal->remote->event;
if(event && part_pending_msgs(portal->remote))
event_set(event);
}
void portal_wait(struct portal *portal)
{
/*
* Notify the other part if needed before waiting.
*/
portal_notify(portal);
/*
* Setup the waiting event.
*/
event_clear(portal->event);
portal->local->event = portal->event;
/*
* Make sure there are no new messages, then wait.
*/
if(!part_pending_msgs(portal->local))
event_wait(portal->event);
/*
* Clear the waiting event.
*/
portal->local->event = 0;
}
bool portal_read(struct portal *portal, message_t *msg)
{
/*
* Make sure there are new messages.
*/
if(!part_pending_msgs(portal->local))
return false;
/*
* Store the message and return.
*/
*msg = part_read(portal->local);
return true;
}
void portal_sync_query(struct portal *portal, message_t msg, size_t msg_id)
{
/*
* Setup the message waiting event.
*/
portal->local->msg_id = 0;
memory_barrier();
event_clear(portal->event);
portal->local->msg_event = portal->event;
/*
* Send the message and wait for the reply.
*/
portal_write_and_notify(portal, msg);
event_wait(portal->event);
/*
* Clear the message waiting event.
*/
portal->local->msg_event = 0;
}
void portal_sync_reply(struct portal *portal, message_t msg, size_t msg_id)
{
/*
* Check if the other side is waiting for this message.
*/
event_t msg_event = portal->remote->msg_event;
memory_barrier();
size_t remote_msg_id = portal->remote->msg_id;
if(msg_event && remote_msg_id == msg_id)
{
/*
* Send the message and trigger the event.
*/
part_write(portal->remote, msg);
event_set(msg_event);
}
else
{
/*
* The other side is not waiting for this message, send it using the regular notify method.
*/
portal_write_and_notify(portal, msg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment