#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().
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 }
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, 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 }
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().
00419 { 00420 int ret = free_spe_context(spe); 00421 00422 __spe_context_update_event(); 00423 00424 return ret; 00425 }
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().
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
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 | ) |
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 }