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

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 }

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_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, 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.

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 }

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

00419 {
00420         int ret = free_spe_context(spe);
00421 
00422         __spe_context_update_event();
00423 
00424         return ret;
00425 }

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

00092 {
00093         pthread_mutex_lock(&spe->base_private->fd_lock[fdesc]);
00094 }

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

00097 {
00098         pthread_mutex_unlock(&spe->base_private->fd_lock[fdesc]);
00099 }

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.

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 }

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.

00428 {
00429         return free_spe_gang_context(gctx);
00430 }

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

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 }

Here is the call graph for this function:


Generated by  doxygen 1.6.2