libspe2 0.9a
create.c
Go to the documentation of this file.
00001 /*
00002  * libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
00003  * Copyright (C) 2005 IBM Corp.
00004  *
00005  * This library is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 2.1 of the License,
00008  * or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00012  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this library; if not, write to the Free Software Foundation,
00017  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  */
00019 
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <pthread.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 
00027 #include <sys/mman.h>
00028 #include <sys/types.h>
00029 #include <sys/spu.h>
00030 #include <sys/stat.h>
00031 #include <unistd.h>
00032 
00033 #include "create.h"
00034 #include "spebase.h"
00035 
00036 
00037 struct fd_attr {
00038         const char *name;
00039         int mode;
00040 };
00041 
00042 static const struct fd_attr spe_fd_attr[NUM_MBOX_FDS] = {
00043         [FD_MBOX]       = { .name = "mbox",      .mode = O_RDONLY },
00044         [FD_MBOX_STAT]  = { .name = "mbox_stat", .mode = O_RDONLY },
00045         [FD_IBOX]       = { .name = "ibox",      .mode = O_RDONLY },
00046         [FD_IBOX_NB]    = { .name = "ibox",      .mode = O_RDONLY |O_NONBLOCK },
00047         [FD_IBOX_STAT]  = { .name = "ibox_stat", .mode = O_RDONLY },
00048         [FD_WBOX]       = { .name = "wbox",      .mode = O_WRONLY },
00049         [FD_WBOX_NB]    = { .name = "wbox",      .mode = O_WRONLY|O_NONBLOCK },
00050         [FD_WBOX_STAT]  = { .name = "wbox_stat", .mode = O_RDONLY },
00051         [FD_SIG1]       = { .name = "signal1",   .mode = O_WRONLY },
00052         [FD_SIG2]       = { .name = "signal2",   .mode = O_WRONLY },
00053         [FD_MFC]        = { .name = "mfc",       .mode = O_RDWR },
00054         [FD_MSS]        = { .name = "mss",       .mode = O_RDWR },
00055 };
00056 
00057 static void *mapfileat(int dir, const char *filename, int size)
00058 {
00059         int fd_temp;
00060         void *ret;
00061 
00062         fd_temp = openat(dir, filename, O_RDWR);
00063         if (fd_temp < 0) {
00064                 DEBUG_PRINTF("ERROR: Could not open SPE %s file.\n", filename);
00065                 errno = EFAULT;
00066                 return MAP_FAILED;
00067         }
00068         ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_temp, 0);
00069         close(fd_temp);
00070 
00071         return ret;
00072 }
00073 
00074 static int setsignotify(int dir, const char *filename)
00075 {
00076         int fd_sig, rc = 0;
00077         char one = '1';
00078 
00079         fd_sig = openat(dir, filename, O_RDWR);
00080         if (fd_sig < 0)
00081                 return -1;
00082 
00083         if (write(fd_sig, &one, sizeof(one)) != sizeof(one))
00084                 rc = -1;
00085 
00086         close(fd_sig);
00087 
00088         return 0;
00089 }
00090 
00091 void _base_spe_context_lock(spe_context_ptr_t spe, enum fd_name fdesc)
00092 {
00093         pthread_mutex_lock(&spe->base_private->fd_lock[fdesc]);
00094 }
00095 
00096 void _base_spe_context_unlock(spe_context_ptr_t spe, enum fd_name fdesc)
00097 {
00098         pthread_mutex_unlock(&spe->base_private->fd_lock[fdesc]);
00099 }
00100 
00101 int _base_spe_open_if_closed(struct spe_context *spe, enum fd_name fdesc, int locked)
00102 {
00103         if (!locked)
00104                 _base_spe_context_lock(spe, fdesc);
00105 
00106         /* already open? */
00107         if (spe->base_private->spe_fds_array[fdesc] != -1) {
00108                 spe->base_private->spe_fds_refcount[fdesc]++;
00109         } else {
00110                 spe->base_private->spe_fds_array[fdesc] =
00111                         openat(spe->base_private->fd_spe_dir,
00112                                         spe_fd_attr[fdesc].name,
00113                                         spe_fd_attr[fdesc].mode);
00114 
00115                 if (spe->base_private->spe_fds_array[(int)fdesc] > 0)
00116                         spe->base_private->spe_fds_refcount[(int)fdesc]++;
00117         }
00118 
00119         if (!locked)
00120                 _base_spe_context_unlock(spe, fdesc);
00121 
00122         return spe->base_private->spe_fds_array[(int)fdesc];
00123 }
00124 
00125 void _base_spe_close_if_open(struct spe_context *spe, enum fd_name fdesc)
00126 {
00127         _base_spe_context_lock(spe, fdesc);
00128 
00129         if (spe->base_private->spe_fds_array[(int)fdesc] != -1 &&
00130                 spe->base_private->spe_fds_refcount[(int)fdesc] == 1) {
00131 
00132                 spe->base_private->spe_fds_refcount[(int)fdesc]--;
00133                 close(spe->base_private->spe_fds_array[(int)fdesc]);
00134 
00135                 spe->base_private->spe_fds_array[(int)fdesc] = -1;
00136         } else if (spe->base_private->spe_fds_refcount[(int)fdesc] > 0) {
00137                 spe->base_private->spe_fds_refcount[(int)fdesc]--;
00138         }
00139 
00140         _base_spe_context_unlock(spe, fdesc);
00141 }
00142 
00143 static int free_spe_context(struct spe_context *spe)
00144 {
00145         int i;
00146 
00147         if (spe->base_private->psmap_mmap_base != MAP_FAILED) {
00148                 munmap(spe->base_private->psmap_mmap_base, PSMAP_SIZE);
00149 
00150         } else {
00151                 if (spe->base_private->mfc_mmap_base != MAP_FAILED)
00152                         munmap(spe->base_private->mfc_mmap_base, MFC_SIZE);
00153                 if (spe->base_private->mssync_mmap_base != MAP_FAILED)
00154                         munmap(spe->base_private->mssync_mmap_base, MSS_SIZE);
00155                 if (spe->base_private->cntl_mmap_base != MAP_FAILED)
00156                         munmap(spe->base_private->cntl_mmap_base, CNTL_SIZE);
00157                 if (spe->base_private->signal1_mmap_base != MAP_FAILED)
00158                         munmap(spe->base_private->signal1_mmap_base,
00159                                         SIGNAL_SIZE);
00160                 if (spe->base_private->signal2_mmap_base != MAP_FAILED)
00161                         munmap(spe->base_private->signal2_mmap_base,
00162                                         SIGNAL_SIZE);
00163         }
00164 
00165         if (spe->base_private->mem_mmap_base != MAP_FAILED)
00166                 munmap(spe->base_private->mem_mmap_base, LS_SIZE);
00167 
00168         for (i = 0; i < NUM_MBOX_FDS; i++) {
00169                 if (spe->base_private->spe_fds_array[i] >= 0)
00170                         close(spe->base_private->spe_fds_array[i]);
00171                 pthread_mutex_destroy(&spe->base_private->fd_lock[i]);
00172         }
00173 
00174         if (spe->base_private->fd_spe_dir >= 0)
00175                 close(spe->base_private->fd_spe_dir);
00176 
00177         free(spe->base_private);
00178         free(spe);
00179 
00180         return 0;
00181 }
00182 
00183 spe_context_ptr_t _base_spe_context_create(unsigned int flags,
00184                 spe_gang_context_ptr_t gctx, spe_context_ptr_t aff_spe)
00185 {
00186         char pathname[256];
00187         int i, aff_spe_fd = 0;
00188         unsigned int spu_createflags = 0;
00189         struct spe_context *spe = NULL;
00190         struct spe_context_base_priv *priv;
00191 
00192         /* We need a loader present to run in emulated isolated mode */
00193         if (flags & SPE_ISOLATE_EMULATE
00194                         && !_base_spe_emulated_loader_present()) {
00195                 errno = EINVAL;
00196                 return NULL;
00197         }
00198 
00199         /* Put some sane defaults into the SPE context */
00200         spe = malloc(sizeof(*spe));
00201         if (!spe) {
00202                 DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
00203                 return NULL;
00204         }
00205         memset(spe, 0, sizeof(*spe));
00206 
00207         spe->base_private = malloc(sizeof(*spe->base_private));
00208         if (!spe->base_private) {
00209                 DEBUG_PRINTF("ERROR: Could not allocate "
00210                                 "spe->base_private context.\n");
00211                 free(spe);
00212                 return NULL;
00213         }
00214 
00215         /* just a convenience variable */
00216         priv = spe->base_private;
00217 
00218         priv->fd_spe_dir = -1;
00219         priv->mem_mmap_base = MAP_FAILED;
00220         priv->psmap_mmap_base = MAP_FAILED;
00221         priv->mssync_mmap_base = MAP_FAILED;
00222         priv->mfc_mmap_base = MAP_FAILED;
00223         priv->cntl_mmap_base = MAP_FAILED;
00224         priv->signal1_mmap_base = MAP_FAILED;
00225         priv->signal2_mmap_base = MAP_FAILED;
00226         priv->loaded_program = NULL;
00227 
00228         for (i = 0; i < NUM_MBOX_FDS; i++) {
00229                 priv->spe_fds_array[i] = -1;
00230                 pthread_mutex_init(&priv->fd_lock[i], NULL);
00231         }
00232 
00233         /* initialise spu_createflags */
00234         if (flags & SPE_ISOLATE) {
00235                 flags |= SPE_MAP_PS;
00236                 spu_createflags |= SPU_CREATE_ISOLATE | SPU_CREATE_NOSCHED;
00237         }
00238 
00239         if (flags & SPE_EVENTS_ENABLE)
00240                 spu_createflags |= SPU_CREATE_EVENTS_ENABLED;
00241 
00242         if (aff_spe)
00243                 spu_createflags |= SPU_CREATE_AFFINITY_SPU;
00244 
00245         if (flags & SPE_AFFINITY_MEMORY)
00246                 spu_createflags |= SPU_CREATE_AFFINITY_MEM;
00247 
00248         /* Make the SPUFS directory for the SPE */
00249         if (gctx == NULL)
00250                 sprintf(pathname, "/spu/spethread-%i-%lu",
00251                         getpid(), (unsigned long)spe);
00252         else
00253                 sprintf(pathname, "/spu/%s/spethread-%i-%lu",
00254                         gctx->base_private->gangname, getpid(),
00255                         (unsigned long)spe);
00256 
00257         if (aff_spe)
00258                 aff_spe_fd = aff_spe->base_private->fd_spe_dir;
00259 
00260         priv->fd_spe_dir = spu_create(pathname, spu_createflags,
00261                         S_IRUSR | S_IWUSR | S_IXUSR, aff_spe_fd);
00262 
00263         if (priv->fd_spe_dir < 0) {
00264                 int errno_saved = errno; /* save errno to prevent being overwritten */
00265                 DEBUG_PRINTF("ERROR: Could not create SPE %s\n", pathname);
00266                 perror("spu_create()");
00267                 free_spe_context(spe);
00268                 /* we mask most errors, but leave ENODEV, etc */
00269                 switch (errno_saved) {
00270                 case ENOTSUP:
00271                 case EEXIST:
00272                 case EINVAL:
00273                 case EBUSY:
00274                 case EPERM:
00275                 case ENODEV:
00276                         errno = errno_saved; /* restore errno */
00277                         break;
00278                 default:
00279                         errno = EFAULT;
00280                         break;
00281                 }
00282                 return NULL;
00283         }
00284 
00285         priv->flags = flags;
00286 
00287         /* Map the required areas into process memory */
00288         priv->mem_mmap_base = mapfileat(priv->fd_spe_dir, "mem", LS_SIZE);
00289         if (priv->mem_mmap_base == MAP_FAILED) {
00290                 DEBUG_PRINTF("ERROR: Could not map SPE memory.\n");
00291                 free_spe_context(spe);
00292                 errno = ENOMEM;
00293                 return NULL;
00294         }
00295 
00296         if (flags & SPE_MAP_PS) {
00297                 /* It's possible to map the entire problem state area with
00298                  * one mmap - try this first */
00299                 priv->psmap_mmap_base =  mapfileat(priv->fd_spe_dir,
00300                                 "psmap", PSMAP_SIZE);
00301 
00302                 if (priv->psmap_mmap_base != MAP_FAILED) {
00303                         priv->mssync_mmap_base =
00304                                 priv->psmap_mmap_base + MSSYNC_OFFSET;
00305                         priv->mfc_mmap_base =
00306                                 priv->psmap_mmap_base + MFC_OFFSET;
00307                         priv->cntl_mmap_base =
00308                                 priv->psmap_mmap_base + CNTL_OFFSET;
00309                         priv->signal1_mmap_base =
00310                                 priv->psmap_mmap_base + SIGNAL1_OFFSET;
00311                         priv->signal2_mmap_base =
00312                                 priv->psmap_mmap_base + SIGNAL2_OFFSET;
00313 
00314                 } else {
00315                         /* map each region separately */
00316                         priv->mfc_mmap_base =
00317                                 mapfileat(priv->fd_spe_dir, "mfc", MFC_SIZE);
00318                         priv->mssync_mmap_base =
00319                                 mapfileat(priv->fd_spe_dir, "mss", MSS_SIZE);
00320                         priv->cntl_mmap_base =
00321                                 mapfileat(priv->fd_spe_dir, "cntl", CNTL_SIZE);
00322                         priv->signal1_mmap_base =
00323                                 mapfileat(priv->fd_spe_dir, "signal1",
00324                                                 SIGNAL_SIZE);
00325                         priv->signal2_mmap_base =
00326                                 mapfileat(priv->fd_spe_dir, "signal2",
00327                                                 SIGNAL_SIZE);
00328 
00329                         if (priv->mfc_mmap_base == MAP_FAILED ||
00330                                         priv->cntl_mmap_base == MAP_FAILED ||
00331                                         priv->signal1_mmap_base == MAP_FAILED ||
00332                                         priv->signal2_mmap_base == MAP_FAILED) {
00333                                 DEBUG_PRINTF("ERROR: Could not map SPE "
00334                                                 "PS memory.\n");
00335                                 free_spe_context(spe);
00336                                 errno = ENOMEM;
00337                                 return NULL;
00338                         }
00339                 }
00340         }
00341 
00342         if (flags & SPE_CFG_SIGNOTIFY1_OR) {
00343                 if (setsignotify(priv->fd_spe_dir, "signal1_type")) {
00344                         DEBUG_PRINTF("ERROR: Could not open SPE "
00345                                         "signal1_type file.\n");
00346                         free_spe_context(spe);
00347                         errno = EFAULT;
00348                         return NULL;
00349                 }
00350         }
00351 
00352         if (flags & SPE_CFG_SIGNOTIFY2_OR) {
00353                 if (setsignotify(priv->fd_spe_dir, "signal2_type")) {
00354                         DEBUG_PRINTF("ERROR: Could not open SPE "
00355                                         "signal2_type file.\n");
00356                         free_spe_context(spe);
00357                         errno = EFAULT;
00358                         return NULL;
00359                 }
00360         }
00361 
00362         return spe;
00363 }
00364 
00365 static int free_spe_gang_context(struct spe_gang_context *gctx)
00366 {
00367         if (gctx->base_private->fd_gang_dir >= 0)
00368                 close(gctx->base_private->fd_gang_dir);
00369 
00370         free(gctx->base_private);
00371         free(gctx);
00372 
00373         return 0;
00374 }
00375 
00376 spe_gang_context_ptr_t _base_spe_gang_context_create(unsigned int flags)
00377 {
00378         char pathname[256];
00379         struct spe_gang_context_base_priv *pgctx = NULL;
00380         struct spe_gang_context *gctx = NULL;
00381 
00382         gctx = malloc(sizeof(*gctx));
00383         if (!gctx) {
00384                 DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
00385                 return NULL;
00386         }
00387         memset(gctx, 0, sizeof(*gctx));
00388 
00389         pgctx = malloc(sizeof(*pgctx));
00390         if (!pgctx) {
00391                 DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
00392                 free(gctx);
00393                 return NULL;
00394         }
00395         memset(pgctx, 0, sizeof(*pgctx));
00396 
00397         gctx->base_private = pgctx;
00398 
00399         sprintf(gctx->base_private->gangname, "gang-%i-%lu", getpid(),
00400                         (unsigned long)gctx);
00401         sprintf(pathname, "/spu/%s", gctx->base_private->gangname);
00402 
00403         gctx->base_private->fd_gang_dir = spu_create(pathname, SPU_CREATE_GANG,
00404                                 S_IRUSR | S_IWUSR | S_IXUSR);
00405 
00406         if (gctx->base_private->fd_gang_dir < 0) {
00407                 DEBUG_PRINTF("ERROR: Could not create Gang %s\n", pathname);
00408                 free_spe_gang_context(gctx);
00409                 errno = EFAULT;
00410                 return NULL;
00411         }
00412 
00413         gctx->base_private->flags = flags;
00414 
00415         return gctx;
00416 }
00417 
00418 int _base_spe_context_destroy(spe_context_ptr_t spe)
00419 {
00420         int ret = free_spe_context(spe);
00421 
00422         __spe_context_update_event();
00423 
00424         return ret;
00425 }
00426 
00427 int _base_spe_gang_context_destroy(spe_gang_context_ptr_t gctx)
00428 {
00429         return free_spe_gang_context(gctx);
00430 }
00431