libspe2 0.9a
Data Structures | Functions
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
gctxspecify NULL if not belonging to a gang
aff_spespecify 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;
}

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:
spectxSpecifies 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:
spectxSpecifies the SPE context
fdSpecifies 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:
spectxSpecifies the SPE context
fdSpecifies 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:
gctxSpecifies 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 
)