create.c File Reference
`#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"`
Include dependency graph for create.c:

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)

## Function Documentation

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);
}

Here is the call graph for this function:

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)

Parameters

  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_context::base_private, spe_gang_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;
}

Here is the call graph for this function:

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.

Parameters

  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;
}

Here is the call graph for this function:

void _base_spe_context_lock | ( | spe_context_ptr_t | spe,
|  | enum fd_name | fd
| ) |  |

_base_spe_context_lock locks members of the SPE context

Parameters

  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

Parameters

  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) |  |

_base_spe_gang_context_destroy destroys a gang context and frees associated resources

Parameters

  gctx | Specifies the SPE gang context

Definition at line 427 of file create.c.

{
return free_spe_gang_context(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];
}

Here is the call graph for this function: