libspe2 0.9a
|
00001 /* 00002 * libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS 00003 * 00004 * Copyright (C) 2006 Sony Computer Entertainment Inc. 00005 * Copyright 2006 Sony Corp. 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include <stdlib.h> 00023 #include "speevent.h" 00024 00025 #include <errno.h> 00026 #include <unistd.h> 00027 #include <sys/epoll.h> 00028 #include <poll.h> 00029 #include <fcntl.h> 00030 00031 #define __SPE_EVENT_ALL \ 00032 ( SPE_EVENT_OUT_INTR_MBOX | SPE_EVENT_IN_MBOX | \ 00033 SPE_EVENT_TAG_GROUP | SPE_EVENT_SPE_STOPPED ) 00034 00035 #define __SPE_EPOLL_SIZE 10 00036 00037 #define __SPE_EPOLL_FD_GET(handler) (*(int*)(handler)) 00038 #define __SPE_EPOLL_FD_SET(handler, fd) (*(int*)(handler) = (fd)) 00039 00040 #define __SPE_EVENT_CONTEXT_PRIV_GET(spe) \ 00041 ( (spe_context_event_priv_ptr_t)(spe)->event_private) 00042 #define __SPE_EVENT_CONTEXT_PRIV_SET(spe, evctx) \ 00043 ( (spe)->event_private = (evctx) ) 00044 00045 #define __SPE_EVENTS_ENABLED(spe) \ 00046 ((spe)->base_private->flags & SPE_EVENTS_ENABLE) 00047 00048 00049 void _event_spe_context_lock(spe_context_ptr_t spe) 00050 { 00051 pthread_mutex_lock(&__SPE_EVENT_CONTEXT_PRIV_GET(spe)->lock); 00052 } 00053 00054 void _event_spe_context_unlock(spe_context_ptr_t spe) 00055 { 00056 pthread_mutex_unlock(&__SPE_EVENT_CONTEXT_PRIV_GET(spe)->lock); 00057 } 00058 00059 int _event_spe_stop_info_read (spe_context_ptr_t spe, spe_stop_info_t *stopinfo) 00060 { 00061 spe_context_event_priv_ptr_t evctx; 00062 int rc; 00063 int fd; 00064 size_t total; 00065 00066 evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe); 00067 fd = evctx->stop_event_pipe[0]; 00068 00069 pthread_mutex_lock(&evctx->stop_event_read_lock); /* for atomic read */ 00070 00071 rc = read(fd, stopinfo, sizeof(*stopinfo)); 00072 if (rc == -1) { 00073 pthread_mutex_unlock(&evctx->stop_event_read_lock); 00074 return -1; 00075 } 00076 00077 total = rc; 00078 while (total < sizeof(*stopinfo)) { /* this loop will be executed in few cases */ 00079 struct pollfd fds; 00080 fds.fd = fd; 00081 fds.events = POLLIN; 00082 rc = poll(&fds, 1, -1); 00083 if (rc == -1) { 00084 if (errno != EINTR) { 00085 break; 00086 } 00087 } 00088 else if (rc == 1) { 00089 rc = read(fd, (char *)stopinfo + total, sizeof(*stopinfo) - total); 00090 if (rc == -1) { 00091 if (errno != EAGAIN) { 00092 break; 00093 } 00094 } 00095 else { 00096 total += rc; 00097 } 00098 } 00099 } 00100 00101 pthread_mutex_unlock(&evctx->stop_event_read_lock); 00102 00103 return rc == -1 ? -1 : 0; 00104 } 00105 00106 /* 00107 * spe_event_handler_create 00108 */ 00109 00110 spe_event_handler_ptr_t _event_spe_event_handler_create(void) 00111 { 00112 int epfd; 00113 spe_event_handler_t *evhandler; 00114 00115 evhandler = calloc(1, sizeof(*evhandler)); 00116 if (!evhandler) { 00117 return NULL; 00118 } 00119 00120 epfd = epoll_create(__SPE_EPOLL_SIZE); 00121 if (epfd == -1) { 00122 free(evhandler); 00123 return NULL; 00124 } 00125 00126 __SPE_EPOLL_FD_SET(evhandler, epfd); 00127 00128 return evhandler; 00129 } 00130 00131 /* 00132 * spe_event_handler_destroy 00133 */ 00134 00135 int _event_spe_event_handler_destroy (spe_event_handler_ptr_t evhandler) 00136 { 00137 int epfd; 00138 00139 if (!evhandler) { 00140 errno = ESRCH; 00141 return -1; 00142 } 00143 00144 epfd = __SPE_EPOLL_FD_GET(evhandler); 00145 close(epfd); 00146 00147 free(evhandler); 00148 return 0; 00149 } 00150 00151 /* 00152 * spe_event_handler_register 00153 */ 00154 00155 int _event_spe_event_handler_register(spe_event_handler_ptr_t evhandler, spe_event_unit_t *event) 00156 { 00157 int epfd; 00158 const int ep_op = EPOLL_CTL_ADD; 00159 spe_context_event_priv_ptr_t evctx; 00160 spe_event_unit_t *ev_buf; 00161 struct epoll_event ep_event; 00162 int fd; 00163 00164 if (!evhandler) { 00165 errno = ESRCH; 00166 return -1; 00167 } 00168 if (!event || !event->spe) { 00169 errno = EINVAL; 00170 return -1; 00171 } 00172 if (!__SPE_EVENTS_ENABLED(event->spe)) { 00173 errno = ENOTSUP; 00174 return -1; 00175 } 00176 00177 epfd = __SPE_EPOLL_FD_GET(evhandler); 00178 evctx = __SPE_EVENT_CONTEXT_PRIV_GET(event->spe); 00179 00180 if (event->events & ~__SPE_EVENT_ALL) { 00181 errno = ENOTSUP; 00182 return -1; 00183 } 00184 00185 _event_spe_context_lock(event->spe); /* for spe->event_private->events */ 00186 00187 if (event->events & SPE_EVENT_OUT_INTR_MBOX) { 00188 fd = __base_spe_event_source_acquire(event->spe, FD_IBOX); 00189 if (fd == -1) { 00190 _event_spe_context_unlock(event->spe); 00191 return -1; 00192 } 00193 00194 ev_buf = &evctx->events[__SPE_EVENT_OUT_INTR_MBOX]; 00195 ev_buf->events = SPE_EVENT_OUT_INTR_MBOX; 00196 ev_buf->data = event->data; 00197 00198 ep_event.events = EPOLLIN; 00199 ep_event.data.ptr = ev_buf; 00200 if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) { 00201 _event_spe_context_unlock(event->spe); 00202 return -1; 00203 } 00204 } 00205 00206 if (event->events & SPE_EVENT_IN_MBOX) { 00207 fd = __base_spe_event_source_acquire(event->spe, FD_WBOX); 00208 if (fd == -1) { 00209 _event_spe_context_unlock(event->spe); 00210 return -1; 00211 } 00212 00213 ev_buf = &evctx->events[__SPE_EVENT_IN_MBOX]; 00214 ev_buf->events = SPE_EVENT_IN_MBOX; 00215 ev_buf->data = event->data; 00216 00217 ep_event.events = EPOLLOUT; 00218 ep_event.data.ptr = ev_buf; 00219 if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) { 00220 _event_spe_context_unlock(event->spe); 00221 return -1; 00222 } 00223 } 00224 00225 if (event->events & SPE_EVENT_TAG_GROUP) { 00226 fd = __base_spe_event_source_acquire(event->spe, FD_MFC); 00227 if (fd == -1) { 00228 _event_spe_context_unlock(event->spe); 00229 return -1; 00230 } 00231 00232 if (event->spe->base_private->flags & SPE_MAP_PS) { 00233 _event_spe_context_unlock(event->spe); 00234 errno = ENOTSUP; 00235 return -1; 00236 } 00237 00238 ev_buf = &evctx->events[__SPE_EVENT_TAG_GROUP]; 00239 ev_buf->events = SPE_EVENT_TAG_GROUP; 00240 ev_buf->data = event->data; 00241 00242 ep_event.events = EPOLLIN; 00243 ep_event.data.ptr = ev_buf; 00244 if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) { 00245 _event_spe_context_unlock(event->spe); 00246 return -1; 00247 } 00248 } 00249 00250 if (event->events & SPE_EVENT_SPE_STOPPED) { 00251 fd = evctx->stop_event_pipe[0]; 00252 00253 ev_buf = &evctx->events[__SPE_EVENT_SPE_STOPPED]; 00254 ev_buf->events = SPE_EVENT_SPE_STOPPED; 00255 ev_buf->data = event->data; 00256 00257 ep_event.events = EPOLLIN; 00258 ep_event.data.ptr = ev_buf; 00259 if (epoll_ctl(epfd, ep_op, fd, &ep_event) == -1) { 00260 _event_spe_context_unlock(event->spe); 00261 return -1; 00262 } 00263 } 00264 00265 _event_spe_context_unlock(event->spe); 00266 00267 return 0; 00268 } 00269 /* 00270 * spe_event_handler_deregister 00271 */ 00272 00273 int _event_spe_event_handler_deregister(spe_event_handler_ptr_t evhandler, spe_event_unit_t *event) 00274 { 00275 int epfd; 00276 const int ep_op = EPOLL_CTL_DEL; 00277 spe_context_event_priv_ptr_t evctx; 00278 int fd; 00279 00280 if (!evhandler) { 00281 errno = ESRCH; 00282 return -1; 00283 } 00284 if (!event || !event->spe) { 00285 errno = EINVAL; 00286 return -1; 00287 } 00288 if (!__SPE_EVENTS_ENABLED(event->spe)) { 00289 errno = ENOTSUP; 00290 return -1; 00291 } 00292 00293 epfd = __SPE_EPOLL_FD_GET(evhandler); 00294 evctx = __SPE_EVENT_CONTEXT_PRIV_GET(event->spe); 00295 00296 if (event->events & ~__SPE_EVENT_ALL) { 00297 errno = ENOTSUP; 00298 return -1; 00299 } 00300 00301 _event_spe_context_lock(event->spe); /* for spe->event_private->events */ 00302 00303 if (event->events & SPE_EVENT_OUT_INTR_MBOX) { 00304 fd = __base_spe_event_source_acquire(event->spe, FD_IBOX); 00305 if (fd == -1) { 00306 _event_spe_context_unlock(event->spe); 00307 return -1; 00308 } 00309 if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) { 00310 _event_spe_context_unlock(event->spe); 00311 return -1; 00312 } 00313 evctx->events[__SPE_EVENT_OUT_INTR_MBOX].events = 0; 00314 } 00315 00316 if (event->events & SPE_EVENT_IN_MBOX) { 00317 fd = __base_spe_event_source_acquire(event->spe, FD_WBOX); 00318 if (fd == -1) { 00319 _event_spe_context_unlock(event->spe); 00320 return -1; 00321 } 00322 if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) { 00323 _event_spe_context_unlock(event->spe); 00324 return -1; 00325 } 00326 evctx->events[__SPE_EVENT_IN_MBOX].events = 0; 00327 } 00328 00329 if (event->events & SPE_EVENT_TAG_GROUP) { 00330 fd = __base_spe_event_source_acquire(event->spe, FD_MFC); 00331 if (fd == -1) { 00332 _event_spe_context_unlock(event->spe); 00333 return -1; 00334 } 00335 if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) { 00336 _event_spe_context_unlock(event->spe); 00337 return -1; 00338 } 00339 evctx->events[__SPE_EVENT_TAG_GROUP].events = 0; 00340 } 00341 00342 if (event->events & SPE_EVENT_SPE_STOPPED) { 00343 fd = evctx->stop_event_pipe[0]; 00344 if (epoll_ctl(epfd, ep_op, fd, NULL) == -1) { 00345 _event_spe_context_unlock(event->spe); 00346 return -1; 00347 } 00348 evctx->events[__SPE_EVENT_SPE_STOPPED].events = 0; 00349 } 00350 00351 _event_spe_context_unlock(event->spe); 00352 00353 return 0; 00354 } 00355 00356 /* 00357 * spe_event_wait 00358 */ 00359 00360 int _event_spe_event_wait(spe_event_handler_ptr_t evhandler, spe_event_unit_t *events, int max_events, int timeout) 00361 { 00362 int epfd; 00363 struct epoll_event *ep_events; 00364 int rc; 00365 00366 if (!evhandler) { 00367 errno = ESRCH; 00368 return -1; 00369 } 00370 if (!events || max_events <= 0) { 00371 errno = EINVAL; 00372 return -1; 00373 } 00374 00375 epfd = __SPE_EPOLL_FD_GET(evhandler); 00376 00377 ep_events = malloc(sizeof(*ep_events) * max_events); 00378 if (!ep_events) { 00379 return -1; 00380 } 00381 00382 for ( ; ; ) { 00383 rc = epoll_wait(epfd, ep_events, max_events, timeout); 00384 if (rc == -1) { /* error */ 00385 if (errno == EINTR) { 00386 if (timeout >= 0) { /* behave as timeout */ 00387 rc = 0; 00388 break; 00389 } 00390 /* else retry */ 00391 } 00392 else { 00393 break; 00394 } 00395 } 00396 else if (rc > 0) { 00397 int i; 00398 for (i = 0; i < rc; i++) { 00399 spe_event_unit_t *ev = (spe_event_unit_t *)(ep_events[i].data.ptr); 00400 _event_spe_context_lock(ev->spe); /* lock ev itself */ 00401 events[i] = *ev; 00402 _event_spe_context_unlock(ev->spe); 00403 } 00404 break; 00405 } 00406 else { /* timeout */ 00407 break; 00408 } 00409 } 00410 00411 free(ep_events); 00412 00413 return rc; 00414 } 00415 00416 int _event_spe_context_finalize(spe_context_ptr_t spe) 00417 { 00418 spe_context_event_priv_ptr_t evctx; 00419 00420 if (!spe) { 00421 errno = ESRCH; 00422 return -1; 00423 } 00424 00425 evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe); 00426 __SPE_EVENT_CONTEXT_PRIV_SET(spe, NULL); 00427 00428 close(evctx->stop_event_pipe[0]); 00429 close(evctx->stop_event_pipe[1]); 00430 00431 pthread_mutex_destroy(&evctx->lock); 00432 pthread_mutex_destroy(&evctx->stop_event_read_lock); 00433 00434 free(evctx); 00435 00436 return 0; 00437 } 00438 00439 struct spe_context_event_priv * _event_spe_context_initialize(spe_context_ptr_t spe) 00440 { 00441 spe_context_event_priv_ptr_t evctx; 00442 int rc; 00443 int i; 00444 00445 evctx = calloc(1, sizeof(*evctx)); 00446 if (!evctx) { 00447 return NULL; 00448 } 00449 00450 rc = pipe(evctx->stop_event_pipe); 00451 if (rc == -1) { 00452 free(evctx); 00453 return NULL; 00454 } 00455 rc = fcntl(evctx->stop_event_pipe[0], F_GETFL); 00456 if (rc != -1) { 00457 rc = fcntl(evctx->stop_event_pipe[0], F_SETFL, rc | O_NONBLOCK); 00458 } 00459 if (rc == -1) { 00460 close(evctx->stop_event_pipe[0]); 00461 close(evctx->stop_event_pipe[1]); 00462 free(evctx); 00463 errno = EIO; 00464 return NULL; 00465 } 00466 00467 for (i = 0; i < sizeof(evctx->events) / sizeof(evctx->events[0]); i++) { 00468 evctx->events[i].spe = spe; 00469 } 00470 00471 pthread_mutex_init(&evctx->lock, NULL); 00472 pthread_mutex_init(&evctx->stop_event_read_lock, NULL); 00473 00474 return evctx; 00475 } 00476 00477 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) 00478 { 00479 spe_context_event_priv_ptr_t evctx; 00480 spe_stop_info_t stopinfo_buf; 00481 int rc; 00482 00483 if (!stopinfo) { 00484 stopinfo = &stopinfo_buf; 00485 } 00486 rc = _base_spe_context_run(spe, entry, runflags, argp, envp, stopinfo); 00487 00488 evctx = __SPE_EVENT_CONTEXT_PRIV_GET(spe); 00489 if (write(evctx->stop_event_pipe[1], stopinfo, sizeof(*stopinfo)) != sizeof(*stopinfo)) { 00490 /* error check. */ 00491 } 00492 00493 return rc; 00494 } 00495