libspe2 0.9a
|
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/spu.h>
#include <sys/stat.h>
#include <unistd.h>
#include "create.h"
#include "spebase.h"
Go to the source code of this file.
Data Structures | |
struct | fd_attr |
Functions | |
void | _base_spe_context_lock (spe_context_ptr_t spe, enum fd_name fdesc) |
void | _base_spe_context_unlock (spe_context_ptr_t spe, enum fd_name fdesc) |
int | _base_spe_open_if_closed (struct spe_context *spe, enum fd_name fdesc, int locked) |
void | _base_spe_close_if_open (struct spe_context *spe, enum fd_name fdesc) |
spe_context_ptr_t | _base_spe_context_create (unsigned int flags, spe_gang_context_ptr_t gctx, spe_context_ptr_t aff_spe) |
spe_gang_context_ptr_t | _base_spe_gang_context_create (unsigned int flags) |
int | _base_spe_context_destroy (spe_context_ptr_t spe) |
int | _base_spe_gang_context_destroy (spe_gang_context_ptr_t gctx) |
void _base_spe_close_if_open | ( | struct spe_context * | spe, |
enum fd_name | fdesc | ||
) |
Definition at line 125 of file create.c.
References _base_spe_context_lock(), _base_spe_context_unlock(), spe_context::base_private, spe_context_base_priv::spe_fds_array, and spe_context_base_priv::spe_fds_refcount.
Referenced by __base_spe_event_source_release(), and _base_spe_signal_write().
{ _base_spe_context_lock(spe, fdesc); if (spe->base_private->spe_fds_array[(int)fdesc] != -1 && spe->base_private->spe_fds_refcount[(int)fdesc] == 1) { spe->base_private->spe_fds_refcount[(int)fdesc]--; close(spe->base_private->spe_fds_array[(int)fdesc]); spe->base_private->spe_fds_array[(int)fdesc] = -1; } else if (spe->base_private->spe_fds_refcount[(int)fdesc] > 0) { spe->base_private->spe_fds_refcount[(int)fdesc]--; } _base_spe_context_unlock(spe, fdesc); }
spe_context_ptr_t _base_spe_context_create | ( | unsigned int | flags, |
spe_gang_context_ptr_t | gctx, | ||
spe_context_ptr_t | aff_spe | ||
) |
_base_spe_context_create creates a single SPE context, i.e., the corresponding directory is created in SPUFS either as a subdirectory of a gang or individually (maybe this is best considered a gang of one)
flags | |
gctx | specify NULL if not belonging to a gang |
aff_spe | specify NULL to skip affinity information |
Definition at line 183 of file create.c.
References _base_spe_emulated_loader_present(), spe_gang_context::base_private, spe_context::base_private, spe_context_base_priv::cntl_mmap_base, CNTL_OFFSET, CNTL_SIZE, DEBUG_PRINTF, spe_context_base_priv::fd_lock, spe_context_base_priv::fd_spe_dir, spe_context_base_priv::flags, spe_gang_context_base_priv::gangname, spe_context_base_priv::loaded_program, LS_SIZE, spe_context_base_priv::mem_mmap_base, spe_context_base_priv::mfc_mmap_base, MFC_OFFSET, MFC_SIZE, MSS_SIZE, spe_context_base_priv::mssync_mmap_base, MSSYNC_OFFSET, NUM_MBOX_FDS, spe_context_base_priv::psmap_mmap_base, PSMAP_SIZE, spe_context_base_priv::signal1_mmap_base, SIGNAL1_OFFSET, spe_context_base_priv::signal2_mmap_base, SIGNAL2_OFFSET, SIGNAL_SIZE, SPE_AFFINITY_MEMORY, SPE_CFG_SIGNOTIFY1_OR, SPE_CFG_SIGNOTIFY2_OR, SPE_EVENTS_ENABLE, spe_context_base_priv::spe_fds_array, SPE_ISOLATE, SPE_ISOLATE_EMULATE, and SPE_MAP_PS.
{ char pathname[256]; int i, aff_spe_fd = 0; unsigned int spu_createflags = 0; struct spe_context *spe = NULL; struct spe_context_base_priv *priv; /* We need a loader present to run in emulated isolated mode */ if (flags & SPE_ISOLATE_EMULATE && !_base_spe_emulated_loader_present()) { errno = EINVAL; return NULL; } /* Put some sane defaults into the SPE context */ spe = malloc(sizeof(*spe)); if (!spe) { DEBUG_PRINTF("ERROR: Could not allocate spe context.\n"); return NULL; } memset(spe, 0, sizeof(*spe)); spe->base_private = malloc(sizeof(*spe->base_private)); if (!spe->base_private) { DEBUG_PRINTF("ERROR: Could not allocate " "spe->base_private context.\n"); free(spe); return NULL; } /* just a convenience variable */ priv = spe->base_private; priv->fd_spe_dir = -1; priv->mem_mmap_base = MAP_FAILED; priv->psmap_mmap_base = MAP_FAILED; priv->mssync_mmap_base = MAP_FAILED; priv->mfc_mmap_base = MAP_FAILED; priv->cntl_mmap_base = MAP_FAILED; priv->signal1_mmap_base = MAP_FAILED; priv->signal2_mmap_base = MAP_FAILED; priv->loaded_program = NULL; for (i = 0; i < NUM_MBOX_FDS; i++) { priv->spe_fds_array[i] = -1; pthread_mutex_init(&priv->fd_lock[i], NULL); } /* initialise spu_createflags */ if (flags & SPE_ISOLATE) { flags |= SPE_MAP_PS; spu_createflags |= SPU_CREATE_ISOLATE | SPU_CREATE_NOSCHED; } if (flags & SPE_EVENTS_ENABLE) spu_createflags |= SPU_CREATE_EVENTS_ENABLED; if (aff_spe) spu_createflags |= SPU_CREATE_AFFINITY_SPU; if (flags & SPE_AFFINITY_MEMORY) spu_createflags |= SPU_CREATE_AFFINITY_MEM; /* Make the SPUFS directory for the SPE */ if (gctx == NULL) sprintf(pathname, "/spu/spethread-%i-%lu", getpid(), (unsigned long)spe); else sprintf(pathname, "/spu/%s/spethread-%i-%lu", gctx->base_private->gangname, getpid(), (unsigned long)spe); if (aff_spe) aff_spe_fd = aff_spe->base_private->fd_spe_dir; priv->fd_spe_dir = spu_create(pathname, spu_createflags, S_IRUSR | S_IWUSR | S_IXUSR, aff_spe_fd); if (priv->fd_spe_dir < 0) { int errno_saved = errno; /* save errno to prevent being overwritten */ DEBUG_PRINTF("ERROR: Could not create SPE %s\n", pathname); perror("spu_create()"); free_spe_context(spe); /* we mask most errors, but leave ENODEV, etc */ switch (errno_saved) { case ENOTSUP: case EEXIST: case EINVAL: case EBUSY: case EPERM: case ENODEV: errno = errno_saved; /* restore errno */ break; default: errno = EFAULT; break; } return NULL; } priv->flags = flags; /* Map the required areas into process memory */ priv->mem_mmap_base = mapfileat(priv->fd_spe_dir, "mem", LS_SIZE); if (priv->mem_mmap_base == MAP_FAILED) { DEBUG_PRINTF("ERROR: Could not map SPE memory.\n"); free_spe_context(spe); errno = ENOMEM; return NULL; } if (flags & SPE_MAP_PS) { /* It's possible to map the entire problem state area with * one mmap - try this first */ priv->psmap_mmap_base = mapfileat(priv->fd_spe_dir, "psmap", PSMAP_SIZE); if (priv->psmap_mmap_base != MAP_FAILED) { priv->mssync_mmap_base = priv->psmap_mmap_base + MSSYNC_OFFSET; priv->mfc_mmap_base = priv->psmap_mmap_base + MFC_OFFSET; priv->cntl_mmap_base = priv->psmap_mmap_base + CNTL_OFFSET; priv->signal1_mmap_base = priv->psmap_mmap_base + SIGNAL1_OFFSET; priv->signal2_mmap_base = priv->psmap_mmap_base + SIGNAL2_OFFSET; } else { /* map each region separately */ priv->mfc_mmap_base = mapfileat(priv->fd_spe_dir, "mfc", MFC_SIZE); priv->mssync_mmap_base = mapfileat(priv->fd_spe_dir, "mss", MSS_SIZE); priv->cntl_mmap_base = mapfileat(priv->fd_spe_dir, "cntl", CNTL_SIZE); priv->signal1_mmap_base = mapfileat(priv->fd_spe_dir, "signal1", SIGNAL_SIZE); priv->signal2_mmap_base = mapfileat(priv->fd_spe_dir, "signal2", SIGNAL_SIZE); if (priv->mfc_mmap_base == MAP_FAILED || priv->cntl_mmap_base == MAP_FAILED || priv->signal1_mmap_base == MAP_FAILED || priv->signal2_mmap_base == MAP_FAILED) { DEBUG_PRINTF("ERROR: Could not map SPE " "PS memory.\n"); free_spe_context(spe); errno = ENOMEM; return NULL; } } } if (flags & SPE_CFG_SIGNOTIFY1_OR) { if (setsignotify(priv->fd_spe_dir, "signal1_type")) { DEBUG_PRINTF("ERROR: Could not open SPE " "signal1_type file.\n"); free_spe_context(spe); errno = EFAULT; return NULL; } } if (flags & SPE_CFG_SIGNOTIFY2_OR) { if (setsignotify(priv->fd_spe_dir, "signal2_type")) { DEBUG_PRINTF("ERROR: Could not open SPE " "signal2_type file.\n"); free_spe_context(spe); errno = EFAULT; return NULL; } } return spe; }
int _base_spe_context_destroy | ( | spe_context_ptr_t | spectx | ) |
_base_spe_context_destroy cleans up what is left when an SPE executable has exited. Closes open file handles and unmaps memory areas.
spectx | Specifies the SPE context |
Definition at line 418 of file create.c.
References __spe_context_update_event().
{ int ret = free_spe_context(spe); __spe_context_update_event(); return ret; }
void _base_spe_context_lock | ( | spe_context_ptr_t | spe, |
enum fd_name | fd | ||
) |
_base_spe_context_lock locks members of the SPE context
spectx | Specifies the SPE context |
fd | Specifies the file |
Definition at line 91 of file create.c.
References spe_context::base_private, and spe_context_base_priv::fd_lock.
Referenced by _base_spe_close_if_open(), and _base_spe_open_if_closed().
{ pthread_mutex_lock(&spe->base_private->fd_lock[fdesc]); }
void _base_spe_context_unlock | ( | spe_context_ptr_t | spe, |
enum fd_name | fd | ||
) |
_base_spe_context_unlock unlocks members of the SPE context
spectx | Specifies the SPE context |
fd | Specifies the file |
Definition at line 96 of file create.c.
References spe_context::base_private, and spe_context_base_priv::fd_lock.
Referenced by _base_spe_close_if_open(), and _base_spe_open_if_closed().
{ pthread_mutex_unlock(&spe->base_private->fd_lock[fdesc]); }
spe_gang_context_ptr_t _base_spe_gang_context_create | ( | unsigned int | flags | ) |
creates the directory in SPUFS that will contain all SPEs that are considered a gang Note: I would like to generalize this to a "group" or "set" Additional attributes maintained at the group level should be used to define scheduling constraints such "temporal" (e.g., scheduled all at the same time, i.e., a gang) "topology" (e.g., "closeness" of SPEs for optimal communication)
Definition at line 376 of file create.c.
References spe_gang_context::base_private, DEBUG_PRINTF, and spe_gang_context_base_priv::gangname.
{ char pathname[256]; struct spe_gang_context_base_priv *pgctx = NULL; struct spe_gang_context *gctx = NULL; gctx = malloc(sizeof(*gctx)); if (!gctx) { DEBUG_PRINTF("ERROR: Could not allocate spe context.\n"); return NULL; } memset(gctx, 0, sizeof(*gctx)); pgctx = malloc(sizeof(*pgctx)); if (!pgctx) { DEBUG_PRINTF("ERROR: Could not allocate spe context.\n"); free(gctx); return NULL; } memset(pgctx, 0, sizeof(*pgctx)); gctx->base_private = pgctx; sprintf(gctx->base_private->gangname, "gang-%i-%lu", getpid(), (unsigned long)gctx); sprintf(pathname, "/spu/%s", gctx->base_private->gangname); gctx->base_private->fd_gang_dir = spu_create(pathname, SPU_CREATE_GANG, S_IRUSR | S_IWUSR | S_IXUSR); if (gctx->base_private->fd_gang_dir < 0) { DEBUG_PRINTF("ERROR: Could not create Gang %s\n", pathname); free_spe_gang_context(gctx); errno = EFAULT; return NULL; } gctx->base_private->flags = flags; return gctx; }
int _base_spe_gang_context_destroy | ( | spe_gang_context_ptr_t | gctx | ) |
int _base_spe_open_if_closed | ( | struct spe_context * | spe, |
enum fd_name | fdesc, | ||
int | locked | ||
) |
Definition at line 101 of file create.c.
References _base_spe_context_lock(), _base_spe_context_unlock(), spe_context::base_private, spe_context_base_priv::fd_spe_dir, fd_attr::mode, fd_attr::name, spe_context_base_priv::spe_fds_array, and spe_context_base_priv::spe_fds_refcount.
Referenced by __base_spe_event_source_acquire(), _base_spe_in_mbox_status(), _base_spe_in_mbox_write(), _base_spe_mssync_start(), _base_spe_mssync_status(), _base_spe_out_intr_mbox_read(), _base_spe_out_intr_mbox_status(), _base_spe_out_mbox_read(), _base_spe_out_mbox_status(), and _base_spe_signal_write().
{ if (!locked) _base_spe_context_lock(spe, fdesc); /* already open? */ if (spe->base_private->spe_fds_array[fdesc] != -1) { spe->base_private->spe_fds_refcount[fdesc]++; } else { spe->base_private->spe_fds_array[fdesc] = openat(spe->base_private->fd_spe_dir, spe_fd_attr[fdesc].name, spe_fd_attr[fdesc].mode); if (spe->base_private->spe_fds_array[(int)fdesc] > 0) spe->base_private->spe_fds_refcount[(int)fdesc]++; } if (!locked) _base_spe_context_unlock(spe, fdesc); return spe->base_private->spe_fds_array[(int)fdesc]; }