libspe2  0.9a
spe_event.c
Go to the documentation of this file.
1 /*
2  * libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
3  *
4  * Copyright (C) 2006 Sony Computer Entertainment Inc.
5  * Copyright 2006 Sony Corp.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <stdlib.h>
23 #include "speevent.h"
24 
25 #include <errno.h>
26 #include <unistd.h>
27 #include <sys/epoll.h>
28 #include <poll.h>
29 #include <fcntl.h>
30 
31 #define __SPE_EVENT_ALL \
32  ( SPE_EVENT_OUT_INTR_MBOX | SPE_EVENT_IN_MBOX | \
33  SPE_EVENT_TAG_GROUP | SPE_EVENT_SPE_STOPPED )
34 
35 #define __SPE_EPOLL_SIZE 10
36 
37 #define __SPE_EPOLL_FD_GET(handler) (*(int*)(handler))
38 #define __SPE_EPOLL_FD_SET(handler, fd) (*(int*)(handler) = (fd))
39 
40 #define __SPE_EVENT_CONTEXT_PRIV_GET(spe) \
41  ( (spe_context_event_priv_ptr_t)(spe)->event_private)
42 #define __SPE_EVENT_CONTEXT_PRIV_SET(spe, evctx) \
43  ( (spe)->event_private = (evctx) )
44 
45 #define __SPE_EVENTS_ENABLED(spe) \
46  ((spe)->base_private->flags & SPE_EVENTS_ENABLE)
47 
48 
50 {
51  pthread_mutex_lock(&__SPE_EVENT_CONTEXT_PRIV_GET(spe)->lock);
52 }
53 
55 {
56  pthread_mutex_unlock(&__SPE_EVENT_CONTEXT_PRIV_GET(spe)->lock);
57 }
58 
60 {
62  int rc;
63  int fd;
64  size_t total;
65 
66  evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe);
67  fd = evctx->stop_event_pipe[0];
68 
69  pthread_mutex_lock(&evctx->stop_event_read_lock); /* for atomic read */
70 
71  rc = read(fd, stopinfo, sizeof(*stopinfo));
72  if (rc == -1) {
73  pthread_mutex_unlock(&evctx->stop_event_read_lock);
74  return -1;
75  }
76 
77  total = rc;
78  while (total < sizeof(*stopinfo)) { /* this loop will be executed in few cases */
79  struct pollfd fds;
80  fds.fd = fd;
81  fds.events = POLLIN;
82  rc = poll(&fds, 1, -1);
83  if (rc == -1) {
84  if (errno != EINTR) {
85  break;
86  }
87  }
88  else if (rc == 1) {
89  rc = read(fd, (char *)stopinfo + total, sizeof(*stopinfo) - total);
90  if (rc == -1) {
91  if (errno != EAGAIN) {
92  break;
93  }
94  }
95  else {
96  total += rc;
97  }
98  }
99  }
100 
101  pthread_mutex_unlock(&evctx->stop_event_read_lock);
102 
103  return rc == -1 ? -1 : 0;
104 }
105 
106 /*
107  * spe_event_handler_create
108  */
109 
111 {
112  int epfd;
113  spe_event_handler_t *evhandler;
114 
115  evhandler = calloc(1, sizeof(*evhandler));
116  if (!evhandler) {
117  return NULL;
118  }
119 
120  epfd = epoll_create(__SPE_EPOLL_SIZE);
121  if (epfd == -1) {
122  free(evhandler);
123  return NULL;
124  }
125 
126  __SPE_EPOLL_FD_SET(evhandler, epfd);
127 
128  return evhandler;
129 }
130 
131 /*
132  * spe_event_handler_destroy
133  */
134 
136 {
137  int epfd;
138 
139  if (!evhandler) {
140  errno = ESRCH;
141  return -1;
142  }
143 
144  epfd = __SPE_EPOLL_FD_GET(evhandler);
145  close(epfd);
146 
147  free(evhandler);
148  return 0;
149 }
150 
151 /*
152  * spe_event_handler_register
153  */
154 
156 {
157  int epfd;
158  const int ep_op = EPOLL_CTL_ADD;
160  spe_event_unit_t *ev_buf;
161  struct epoll_event ep_event;
162  int fd;
163 
164  if (!evhandler) {
165  errno = ESRCH;
166  return -1;
167  }
168  if (!event || !event->spe) {
169  errno = EINVAL;
170  return -1;
171  }
172  if (!__SPE_EVENTS_ENABLED(event->spe)) {
173  errno = ENOTSUP;
174  return -1;
175  }
176 
177  epfd = __SPE_EPOLL_FD_GET(evhandler);
178  evctx = __SPE_EVENT_CONTEXT_PRIV_GET(event->spe);
179 
180  if (event->events & ~__SPE_EVENT_ALL) {
181  errno = ENOTSUP;
182  return -1;
183  }
184 
185  _event_spe_context_lock(event->spe); /* for spe->event_private->events */
186 
187  if (event->events & SPE_EVENT_OUT_INTR_MBOX) {
189  if (fd == -1) {
191  return -1;
192  }
193 
194  ev_buf = &evctx->events[__SPE_EVENT_OUT_INTR_MBOX];
196  ev_buf->data = event->data;
197 
198  ep_event.events = EPOLLIN;
199  ep_event.data.ptr = ev_buf;
200  if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) {
202  return -1;
203  }
204  }
205 
206  if (event->events & SPE_EVENT_IN_MBOX) {
208  if (fd == -1) {
210  return -1;
211  }
212 
213  ev_buf = &evctx->events[__SPE_EVENT_IN_MBOX];
214  ev_buf->events = SPE_EVENT_IN_MBOX;
215  ev_buf->data = event->data;
216 
217  ep_event.events = EPOLLOUT;
218  ep_event.data.ptr = ev_buf;
219  if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) {
221  return -1;
222  }
223  }
224 
225  if (event->events & SPE_EVENT_TAG_GROUP) {
227  if (fd == -1) {
229  return -1;
230  }
231 
232  if (event->spe->base_private->flags & SPE_MAP_PS) {
234  errno = ENOTSUP;
235  return -1;
236  }
237 
238  ev_buf = &evctx->events[__SPE_EVENT_TAG_GROUP];
239  ev_buf->events = SPE_EVENT_TAG_GROUP;
240  ev_buf->data = event->data;
241 
242  ep_event.events = EPOLLIN;
243  ep_event.data.ptr = ev_buf;
244  if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) {
246  return -1;
247  }
248  }
249 
250  if (event->events & SPE_EVENT_SPE_STOPPED) {
251  fd = evctx->stop_event_pipe[0];
252 
253  ev_buf = &evctx->events[__SPE_EVENT_SPE_STOPPED];
254  ev_buf->events = SPE_EVENT_SPE_STOPPED;
255  ev_buf->data = event->data;
256 
257  ep_event.events = EPOLLIN;
258  ep_event.data.ptr = ev_buf;
259  if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) {
261  return -1;
262  }
263  }
264 
266 
267  return 0;
268 }
269 /*
270  * spe_event_handler_deregister
271  */
272 
274 {
275  int epfd;
276  const int ep_op = EPOLL_CTL_DEL;
278  int fd;
279 
280  if (!evhandler) {
281  errno = ESRCH;
282  return -1;
283  }
284  if (!event || !event->spe) {
285  errno = EINVAL;
286  return -1;
287  }
288  if (!__SPE_EVENTS_ENABLED(event->spe)) {
289  errno = ENOTSUP;
290  return -1;
291  }
292 
293  epfd = __SPE_EPOLL_FD_GET(evhandler);
294  evctx = __SPE_EVENT_CONTEXT_PRIV_GET(event->spe);
295 
296  if (event->events & ~__SPE_EVENT_ALL) {
297  errno = ENOTSUP;
298  return -1;
299  }
300 
301  _event_spe_context_lock(event->spe); /* for spe->event_private->events */
302 
303  if (event->events & SPE_EVENT_OUT_INTR_MBOX) {
305  if (fd == -1) {
307  return -1;
308  }
309  if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) {
311  return -1;
312  }
314  }
315 
316  if (event->events & SPE_EVENT_IN_MBOX) {
318  if (fd == -1) {
320  return -1;
321  }
322  if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) {
324  return -1;
325  }
326  evctx->events[__SPE_EVENT_IN_MBOX].events = 0;
327  }
328 
329  if (event->events & SPE_EVENT_TAG_GROUP) {
331  if (fd == -1) {
333  return -1;
334  }
335  if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) {
337  return -1;
338  }
339  evctx->events[__SPE_EVENT_TAG_GROUP].events = 0;
340  }
341 
342  if (event->events & SPE_EVENT_SPE_STOPPED) {
343  fd = evctx->stop_event_pipe[0];
344  if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) {
346  return -1;
347  }
349  }
350 
352 
353  return 0;
354 }
355 
356 /*
357  * spe_event_wait
358  */
359 
360 int _event_spe_event_wait(spe_event_handler_ptr_t evhandler, spe_event_unit_t *events, int max_events, int timeout)
361 {
362  int epfd;
363  struct epoll_event *ep_events;
364  int rc;
365 
366  if (!evhandler) {
367  errno = ESRCH;
368  return -1;
369  }
370  if (!events || max_events <= 0) {
371  errno = EINVAL;
372  return -1;
373  }
374 
375  epfd = __SPE_EPOLL_FD_GET(evhandler);
376 
377  ep_events = malloc(sizeof(*ep_events) * max_events);
378  if (!ep_events) {
379  return -1;
380  }
381 
382  for ( ; ; ) {
383  rc = epoll_wait(epfd, ep_events, max_events, timeout);
384  if (rc == -1) { /* error */
385  if (errno == EINTR) {
386  if (timeout >= 0) { /* behave as timeout */
387  rc = 0;
388  break;
389  }
390  /* else retry */
391  }
392  else {
393  break;
394  }
395  }
396  else if (rc > 0) {
397  int i;
398  for (i = 0; i < rc; i++) {
399  spe_event_unit_t *ev = (spe_event_unit_t *)(ep_events[i].data.ptr);
400  _event_spe_context_lock(ev->spe); /* lock ev itself */
401  events[i] = *ev;
403  }
404  break;
405  }
406  else { /* timeout */
407  break;
408  }
409  }
410 
411  free(ep_events);
412 
413  return rc;
414 }
415 
417 {
419 
420  if (!spe) {
421  errno = ESRCH;
422  return -1;
423  }
424 
425  evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe);
426  __SPE_EVENT_CONTEXT_PRIV_SET(spe, NULL);
427 
428  close(evctx->stop_event_pipe[0]);
429  close(evctx->stop_event_pipe[1]);
430 
431  pthread_mutex_destroy(&evctx->lock);
432  pthread_mutex_destroy(&evctx->stop_event_read_lock);
433 
434  free(evctx);
435 
436  return 0;
437 }
438 
440 {
442  int rc;
443  int i;
444 
445  evctx = calloc(1, sizeof(*evctx));
446  if (!evctx) {
447  return NULL;
448  }
449 
450  rc = pipe(evctx->stop_event_pipe);
451  if (rc == -1) {
452  free(evctx);
453  return NULL;
454  }
455  rc = fcntl(evctx->stop_event_pipe[0], F_GETFL);
456  if (rc != -1) {
457  rc = fcntl(evctx->stop_event_pipe[0], F_SETFL, rc | O_NONBLOCK);
458  }
459  if (rc == -1) {
460  close(evctx->stop_event_pipe[0]);
461  close(evctx->stop_event_pipe[1]);
462  free(evctx);
463  errno = EIO;
464  return NULL;
465  }
466 
467  for (i = 0; i < sizeof(evctx->events) / sizeof(evctx->events[0]); i++) {
468  evctx->events[i].spe = spe;
469  }
470 
471  pthread_mutex_init(&evctx->lock, NULL);
472  pthread_mutex_init(&evctx->stop_event_read_lock, NULL);
473 
474  return evctx;
475 }
476 
477 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)
478 {
480  spe_stop_info_t stopinfo_buf;
481  int rc;
482 
483  if (!stopinfo) {
484  stopinfo = &stopinfo_buf;
485  }
486  rc = _base_spe_context_run(spe, entry, runflags, argp, envp, stopinfo);
487 
488  evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe);
489  if (write(evctx->stop_event_pipe[1], stopinfo, sizeof(*stopinfo)) != sizeof(*stopinfo)) {
490  /* error check. */
491  }
492 
493  return rc;
494 }
495