spe_event.c File Reference
`#include <stdlib.h>`
`#include "speevent.h"`
`#include <errno.h>`
`#include <unistd.h>`
`#include <sys/epoll.h>`
`#include <poll.h>`
`#include <fcntl.h>`
Include dependency graph for spe_event.c:

Go to the source code of this file.

## Macros

#define | __SPE_EVENT_ALL
#define | __SPE_EPOLL_SIZE 10
#define | __SPE_EPOLL_FD_GET(handler) (*(int*)(handler))
#define | __SPE_EPOLL_FD_SET(handler, fd) (*(int*)(handler) = (fd))
#define | __SPE_EVENT_CONTEXT_PRIV_GET(spe) ( (spe_context_event_priv_ptr_t)(spe)->event_private)
#define | __SPE_EVENT_CONTEXT_PRIV_SET(spe, evctx) ( (spe)->event_private = (evctx) )
#define | __SPE_EVENTS_ENABLED(spe) ((spe)->base_private->flags & SPE_EVENTS_ENABLE)

## Functions

void | _event_spe_context_lock (spe_context_ptr_t spe)
void | _event_spe_context_unlock (spe_context_ptr_t spe)
int | _event_spe_stop_info_read (spe_context_ptr_t spe, spe_stop_info_t *stopinfo)
spe_event_handler_ptr_t | _event_spe_event_handler_create (void)
int | _event_spe_event_handler_destroy (spe_event_handler_ptr_t evhandler)
int | _event_spe_event_handler_register (spe_event_handler_ptr_t evhandler, spe_event_unit_t *event)
int | _event_spe_event_handler_deregister (spe_event_handler_ptr_t evhandler, spe_event_unit_t *event)
int | _event_spe_event_wait (spe_event_handler_ptr_t evhandler, spe_event_unit_t *events, int max_events, int timeout)
int | _event_spe_context_finalize (spe_context_ptr_t spe)
struct spe_context_event_priv * | _event_spe_context_initialize (spe_context_ptr_t spe)
int | _event_spe_context_run (spe_context_ptr_t spe, unsigned int *entry, unsigned int runflags, void *argp, void *envp, spe_stop_info_t *stopinfo)

## Macro Definition Documentation

#define __SPE_EPOLL_FD_GET | ( |  | handler) |  | (*(int*)(handler))

Definition at line 37 of file spe_event.c.

Referenced by _event_spe_event_handler_deregister(), _event_spe_event_handler_destroy(), _event_spe_event_handler_register(), and _event_spe_event_wait().

#define __SPE_EPOLL_FD_SET | ( |  | handler,
|  |  | fd
| ) |  | (*(int*)(handler) = (fd))

Definition at line 38 of file spe_event.c.

Referenced by _event_spe_event_handler_create().

#define __SPE_EPOLL_SIZE 10

Definition at line 35 of file spe_event.c.

Referenced by _event_spe_event_handler_create().

#define __SPE_EVENT_ALL

Value:
( SPE_EVENT_OUT_INTR_MBOX | SPE_EVENT_IN_MBOX | \
SPE_EVENT_TAG_GROUP | SPE_EVENT_SPE_STOPPED )

Definition at line 31 of file spe_event.c.

Referenced by _event_spe_event_handler_deregister(), and _event_spe_event_handler_register().

#define __SPE_EVENT_CONTEXT_PRIV_GET | ( |  | spe) |  | ( (spe_context_event_priv_ptr_t)(spe)->event_private)

Definition at line 40 of file spe_event.c.

Referenced by _event_spe_context_finalize(), _event_spe_context_lock(), _event_spe_context_run(), _event_spe_context_unlock(), _event_spe_event_handler_deregister(), _event_spe_event_handler_register(), and _event_spe_stop_info_read().

#define __SPE_EVENT_CONTEXT_PRIV_SET | ( |  | spe,
|  |  | evctx
| ) |  | ( (spe)->event_private = (evctx) )

Definition at line 42 of file spe_event.c.

Referenced by _event_spe_context_finalize().

#define __SPE_EVENTS_ENABLED | ( |  | spe) |  | ((spe)->base_private->flags & SPE_EVENTS_ENABLE)

Definition at line 45 of file spe_event.c.

Referenced by _event_spe_event_handler_deregister(), and _event_spe_event_handler_register().

## Function Documentation

int _event_spe_context_finalize | ( | spe_context_ptr_t | spe) |  |

Definition at line 416 of file spe_event.c.

References __SPE_EVENT_CONTEXT_PRIV_GET, __SPE_EVENT_CONTEXT_PRIV_SET, spe_context_event_priv::lock, spe_context_event_priv::stop_event_pipe, and spe_context_event_priv::stop_event_read_lock.

{
spe_context_event_priv_ptr_t evctx;
if (!spe) {
errno = ESRCH;
return -1;
}
evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe);
__SPE_EVENT_CONTEXT_PRIV_SET(spe, NULL);
close(evctx->stop_event_pipe[0]);
close(evctx->stop_event_pipe[1]);
pthread_mutex_destroy(&evctx->lock);
pthread_mutex_destroy(&evctx->stop_event_read_lock);
free(evctx);
return 0;
}

struct spe_context_event_priv* _event_spe_context_initialize | ( | spe_context_ptr_t | spe) |  |

Definition at line 439 of file spe_event.c.

References spe_context_event_priv::events, spe_context_event_priv::lock, spe_event_unit::spe, spe_context_event_priv::stop_event_pipe, and spe_context_event_priv::stop_event_read_lock.

{
spe_context_event_priv_ptr_t evctx;
int rc;
int i;
evctx = calloc(1, sizeof(*evctx));
if (!evctx) {
return NULL;
}
rc = pipe(evctx->stop_event_pipe);
if (rc == -1) {
free(evctx);
return NULL;
}
rc = fcntl(evctx->stop_event_pipe[0], F_GETFL);
if (rc != -1) {
rc = fcntl(evctx->stop_event_pipe[0], F_SETFL, rc | O_NONBLOCK);
}
if (rc == -1) {
close(evctx->stop_event_pipe[0]);
close(evctx->stop_event_pipe[1]);
free(evctx);
errno = EIO;
return NULL;
}
for (i = 0; i < sizeof(evctx->events) / sizeof(evctx->events[0]); i++) {
evctx->events[i].spe = spe;
}
pthread_mutex_init(&evctx->lock, NULL);
pthread_mutex_init(&evctx->stop_event_read_lock, NULL);
return evctx;
}

void _event_spe_context_lock | ( | spe_context_ptr_t | spe) |  |

Definition at line 49 of file spe_event.c.

References __SPE_EVENT_CONTEXT_PRIV_GET.

Referenced by _event_spe_event_handler_deregister(), _event_spe_event_handler_register(), and _event_spe_event_wait().

{
pthread_mutex_lock(&__SPE_EVENT_CONTEXT_PRIV_GET(spe)->lock);
}

int _event_spe_context_run | ( | spe_context_ptr_t | spe,
|  | unsigned int * | entry,
|  | unsigned int | runflags,
|  | void * | argp,
|  | void * | envp,
|  | spe_stop_info_t * | stopinfo
| ) |  |

Definition at line 477 of file spe_event.c.

References __SPE_EVENT_CONTEXT_PRIV_GET, _base_spe_context_run(), and spe_context_event_priv::stop_event_pipe.

{
spe_context_event_priv_ptr_t evctx;
spe_stop_info_t stopinfo_buf;
int rc;
if (!stopinfo) {
stopinfo = &stopinfo_buf;
}
rc = _base_spe_context_run(spe, entry, runflags, argp, envp, stopinfo);
evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe);
if (write(evctx->stop_event_pipe[1], stopinfo, sizeof(*stopinfo)) != sizeof(*stopinfo)) {
/* error check. */
}
return rc;
}

Here is the call graph for this function:

void _event_spe_context_unlock | ( | spe_context_ptr_t | spe) |  |

Definition at line 54 of file spe_event.c.

References __SPE_EVENT_CONTEXT_PRIV_GET.

Referenced by _event_spe_event_handler_deregister(), _event_spe_event_handler_register(), and _event_spe_event_wait().

{
pthread_mutex_unlock(&__SPE_EVENT_CONTEXT_PRIV_GET(spe)->lock);
}

spe_event_handler_ptr_t _event_spe_event_handler_create | ( | void | ) |  |

Definition at line 110 of file spe_event.c.

References __SPE_EPOLL_FD_SET, and __SPE_EPOLL_SIZE.

{
int epfd;
spe_event_handler_t *evhandler;
evhandler = calloc(1, sizeof(*evhandler));
if (!evhandler) {
return NULL;
}
epfd = epoll_create(__SPE_EPOLL_SIZE);
if (epfd == -1) {
free(evhandler);
return NULL;
}
__SPE_EPOLL_FD_SET(evhandler, epfd);
return evhandler;
}

int _event_spe_event_handler_deregister | ( | spe_event_handler_ptr_t | evhandler,
|  | spe_event_unit_t * | event
| ) |  |

Definition at line 273 of file spe_event.c.

References __base_spe_event_source_acquire(), __SPE_EPOLL_FD_GET, __SPE_EVENT_ALL, __SPE_EVENT_CONTEXT_PRIV_GET, __SPE_EVENT_IN_MBOX, __SPE_EVENT_OUT_INTR_MBOX, __SPE_EVENT_SPE_STOPPED, __SPE_EVENT_TAG_GROUP, __SPE_EVENTS_ENABLED, _event_spe_context_lock(), _event_spe_context_unlock(), spe_context_event_priv::events, spe_event_unit::events, FD_IBOX, FD_MFC, FD_WBOX, spe_event_unit::spe, SPE_EVENT_IN_MBOX, SPE_EVENT_OUT_INTR_MBOX, SPE_EVENT_SPE_STOPPED, SPE_EVENT_TAG_GROUP, and spe_context_event_priv::stop_event_pipe.

{
int epfd;
const int ep_op = EPOLL_CTL_DEL;
spe_context_event_priv_ptr_t evctx;
int fd;
if (!evhandler) {
errno = ESRCH;
return -1;
}
if (!event || !event->spe) {
errno = EINVAL;
return -1;
}
if (!__SPE_EVENTS_ENABLED(event->spe)) {
errno = ENOTSUP;
return -1;
}
epfd = __SPE_EPOLL_FD_GET(evhandler);
evctx = __SPE_EVENT_CONTEXT_PRIV_GET(event->spe);
if (event->events & ~__SPE_EVENT_ALL) {
errno = ENOTSUP;
return -1;
}
_event_spe_context_lock(event->spe); /* for spe->event_private->events */
if (event->events & SPE_EVENT_OUT_INTR_MBOX) {
fd = __base_spe_event_source_acquire(event->spe, FD_IBOX);
if (fd == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
evctx->events[__SPE_EVENT_OUT_INTR_MBOX].events = 0;
}
if (event->events & SPE_EVENT_IN_MBOX) {
fd = __base_spe_event_source_acquire(event->spe, FD_WBOX);
if (fd == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
evctx->events[__SPE_EVENT_IN_MBOX].events = 0;
}
if (event->events & SPE_EVENT_TAG_GROUP) {
fd = __base_spe_event_source_acquire(event->spe, FD_MFC);
if (fd == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
evctx->events[__SPE_EVENT_TAG_GROUP].events = 0;
}
if (event->events & SPE_EVENT_SPE_STOPPED) {
fd = evctx->stop_event_pipe[0];
if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
evctx->events[__SPE_EVENT_SPE_STOPPED].events = 0;
}
_event_spe_context_unlock(event->spe);
return 0;
}

Here is the call graph for this function:

int _event_spe_event_handler_destroy | ( | spe_event_handler_ptr_t | evhandler) |  |

Definition at line 135 of file spe_event.c.

References __SPE_EPOLL_FD_GET.

{
int epfd;
if (!evhandler) {
errno = ESRCH;
return -1;
}
epfd = __SPE_EPOLL_FD_GET(evhandler);
close(epfd);
free(evhandler);
return 0;
}

int _event_spe_event_handler_register | ( | spe_event_handler_ptr_t | evhandler,
|  | spe_event_unit_t * | event
| ) |  |

Definition at line 155 of file spe_event.c.

References __base_spe_event_source_acquire(), __SPE_EPOLL_FD_GET, __SPE_EVENT_ALL, __SPE_EVENT_CONTEXT_PRIV_GET, __SPE_EVENT_IN_MBOX, __SPE_EVENT_OUT_INTR_MBOX, __SPE_EVENT_SPE_STOPPED, __SPE_EVENT_TAG_GROUP, __SPE_EVENTS_ENABLED, _event_spe_context_lock(), _event_spe_context_unlock(), spe_context::base_private, spe_event_unit::data, spe_context_event_priv::events, spe_event_unit::events, FD_IBOX, FD_MFC, FD_WBOX, spe_context_base_priv::flags, spe_event_data::ptr, spe_event_unit::spe, SPE_EVENT_IN_MBOX, SPE_EVENT_OUT_INTR_MBOX, SPE_EVENT_SPE_STOPPED, SPE_EVENT_TAG_GROUP, SPE_MAP_PS, and spe_context_event_priv::stop_event_pipe.

{
int epfd;
const int ep_op = EPOLL_CTL_ADD;
spe_context_event_priv_ptr_t evctx;
spe_event_unit_t *ev_buf;
struct epoll_event ep_event;
int fd;
if (!evhandler) {
errno = ESRCH;
return -1;
}
if (!event || !event->spe) {
errno = EINVAL;
return -1;
}
if (!__SPE_EVENTS_ENABLED(event->spe)) {
errno = ENOTSUP;
return -1;
}
epfd = __SPE_EPOLL_FD_GET(evhandler);
evctx = __SPE_EVENT_CONTEXT_PRIV_GET(event->spe);
if (event->events & ~__SPE_EVENT_ALL) {
errno = ENOTSUP;
return -1;
}
_event_spe_context_lock(event->spe); /* for spe->event_private->events */
if (event->events & SPE_EVENT_OUT_INTR_MBOX) {
fd = __base_spe_event_source_acquire(event->spe, FD_IBOX);
if (fd == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
ev_buf = &evctx->events[__SPE_EVENT_OUT_INTR_MBOX];
ev_buf->events = SPE_EVENT_OUT_INTR_MBOX;
ev_buf->data = event->data;
ep_event.events = EPOLLIN;
ep_event.data.ptr = ev_buf;
if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
}
if (event->events & SPE_EVENT_IN_MBOX) {
fd = __base_spe_event_source_acquire(event->spe, FD_WBOX);
if (fd == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
ev_buf = &evctx->events[__SPE_EVENT_IN_MBOX];
ev_buf->events = SPE_EVENT_IN_MBOX;
ev_buf->data = event->data;
ep_event.events = EPOLLOUT;
ep_event.data.ptr = ev_buf;
if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
}
if (event->events & SPE_EVENT_TAG_GROUP) {
fd = __base_spe_event_source_acquire(event->spe, FD_MFC);
if (fd == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
if (event->spe->base_private->flags & SPE_MAP_PS) {
_event_spe_context_unlock(event->spe);
errno = ENOTSUP;
return -1;
}
ev_buf = &evctx->events[__SPE_EVENT_TAG_GROUP];
ev_buf->events = SPE_EVENT_TAG_GROUP;
ev_buf->data = event->data;
ep_event.events = EPOLLIN;
ep_event.data.ptr = ev_buf;
if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
}
if (event->events & SPE_EVENT_SPE_STOPPED) {
fd = evctx->stop_event_pipe[0];
ev_buf = &evctx->events[__SPE_EVENT_SPE_STOPPED];
ev_buf->events = SPE_EVENT_SPE_STOPPED;
ev_buf->data = event->data;
ep_event.events = EPOLLIN;
ep_event.data.ptr = ev_buf;
if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) {
_event_spe_context_unlock(event->spe);
return -1;
}
}
_event_spe_context_unlock(event->spe);
return 0;
}

Here is the call graph for this function:

int _event_spe_event_wait | ( | spe_event_handler_ptr_t | evhandler,
|  | spe_event_unit_t * | events,
|  | int | max_events,
|  | int | timeout
| ) |  |

Definition at line 360 of file spe_event.c.

References __SPE_EPOLL_FD_GET, _event_spe_context_lock(), _event_spe_context_unlock(), and spe_event_unit::spe.

{
int epfd;
struct epoll_event *ep_events;
int rc;
if (!evhandler) {
errno = ESRCH;
return -1;
}
if (!events || max_events <= 0) {
errno = EINVAL;
return -1;
}
epfd = __SPE_EPOLL_FD_GET(evhandler);
ep_events = malloc(sizeof(*ep_events) * max_events);
if (!ep_events) {
return -1;
}
for ( ; ; ) {
rc = epoll_wait(epfd, ep_events, max_events, timeout);
if (rc == -1) { /* error */
if (errno == EINTR) {
if (timeout >= 0) { /* behave as timeout */
rc = 0;
break;
}
/* else retry */
}
else {
break;
}
}
else if (rc > 0) {
int i;
for (i = 0; i < rc; i++) {
spe_event_unit_t *ev = (spe_event_unit_t *)(ep_events[i].data.ptr);
_event_spe_context_lock(ev->spe); /* lock ev itself */
events[i] = *ev;
_event_spe_context_unlock(ev->spe);
}
break;
}
else { /* timeout */
break;
}
}
free(ep_events);
return rc;
}

Here is the call graph for this function:

int _event_spe_stop_info_read | ( | spe_context_ptr_t | spe,
|  | spe_stop_info_t * | stopinfo
| ) |  |

Definition at line 59 of file spe_event.c.

References __SPE_EVENT_CONTEXT_PRIV_GET, spe_context_event_priv::stop_event_pipe, and spe_context_event_priv::stop_event_read_lock.

{
spe_context_event_priv_ptr_t evctx;
int rc;
int fd;
size_t total;
evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe);
fd = evctx->stop_event_pipe[0];
pthread_mutex_lock(&evctx->stop_event_read_lock); /* for atomic read */
rc = read(fd, stopinfo, sizeof(*stopinfo));
if (rc == -1) {
pthread_mutex_unlock(&evctx->stop_event_read_lock);
return -1;
}
total = rc;
while (total < sizeof(*stopinfo)) { /* this loop will be executed in few cases */
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN;
rc = poll(&fds, 1, -1);
if (rc == -1) {
if (errno != EINTR) {
break;
}
}
else if (rc == 1) {
rc = read(fd, (char *)stopinfo + total, sizeof(*stopinfo) - total);
if (rc == -1) {
if (errno != EAGAIN) {
break;
}
}
else {
total += rc;
}
}
}
pthread_mutex_unlock(&evctx->stop_event_read_lock);
return rc == -1 ? -1 : 0;
}