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

126 {
127  _base_spe_context_lock(spe, fdesc);
128 
129  if (spe->base_private->spe_fds_array[(int)fdesc] != -1 &&
130  spe->base_private->spe_fds_refcount[(int)fdesc] == 1) {
131 
132  spe->base_private->spe_fds_refcount[(int)fdesc]--;
133  close(spe->base_private->spe_fds_array[(int)fdesc]);
134 
135  spe->base_private->spe_fds_array[(int)fdesc] = -1;
136  } else if (spe->base_private->spe_fds_refcount[(int)fdesc] > 0) {
137  spe->base_private->spe_fds_refcount[(int)fdesc]--;
138  }
139 
140  _base_spe_context_unlock(spe, fdesc);
141 }

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

185 {
186  char pathname[256];
187  int i, aff_spe_fd = 0;
188  unsigned int spu_createflags = 0;
189  struct spe_context *spe = NULL;
190  struct spe_context_base_priv *priv;
191 
192  /* We need a loader present to run in emulated isolated mode */
195  errno = EINVAL;
196  return NULL;
197  }
198 
199  /* Put some sane defaults into the SPE context */
200  spe = malloc(sizeof(*spe));
201  if (!spe) {
202  DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
203  return NULL;
204  }
205  memset(spe, 0, sizeof(*spe));
206 
207  spe->base_private = malloc(sizeof(*spe->base_private));
208  if (!spe->base_private) {
209  DEBUG_PRINTF("ERROR: Could not allocate "
210  "spe->base_private context.\n");
211  free(spe);
212  return NULL;
213  }
214 
215  /* just a convenience variable */
216  priv = spe->base_private;
217 
218  priv->fd_spe_dir = -1;
219  priv->mem_mmap_base = MAP_FAILED;
220  priv->psmap_mmap_base = MAP_FAILED;
221  priv->mssync_mmap_base = MAP_FAILED;
222  priv->mfc_mmap_base = MAP_FAILED;
223  priv->cntl_mmap_base = MAP_FAILED;
224  priv->signal1_mmap_base = MAP_FAILED;
225  priv->signal2_mmap_base = MAP_FAILED;
226  priv->loaded_program = NULL;
227 
228  for (i = 0; i < NUM_MBOX_FDS; i++) {
229  priv->spe_fds_array[i] = -1;
230  pthread_mutex_init(&priv->fd_lock[i], NULL);
231  }
232 
233  /* initialise spu_createflags */
234  if (flags & SPE_ISOLATE) {
235  flags |= SPE_MAP_PS;
236  spu_createflags |= SPU_CREATE_ISOLATE | SPU_CREATE_NOSCHED;
237  }
238 
239  if (flags & SPE_EVENTS_ENABLE)
240  spu_createflags |= SPU_CREATE_EVENTS_ENABLED;
241 
242  if (aff_spe)
243  spu_createflags |= SPU_CREATE_AFFINITY_SPU;
244 
246  spu_createflags |= SPU_CREATE_AFFINITY_MEM;
247 
248  /* Make the SPUFS directory for the SPE */
249  if (gctx == NULL)
250  sprintf(pathname, "/spu/spethread-%i-%lu",
251  getpid(), (unsigned long)spe);
252  else
253  sprintf(pathname, "/spu/%s/spethread-%i-%lu",
254  gctx->base_private->gangname, getpid(),
255  (unsigned long)spe);
256 
257  if (aff_spe)
258  aff_spe_fd = aff_spe->base_private->fd_spe_dir;
259 
260  priv->fd_spe_dir = spu_create(pathname, spu_createflags,
261  S_IRUSR | S_IWUSR | S_IXUSR, aff_spe_fd);
262 
263  if (priv->fd_spe_dir < 0) {
264  int errno_saved = errno; /* save errno to prevent being overwritten */
265  DEBUG_PRINTF("ERROR: Could not create SPE %s\n", pathname);
266  perror("spu_create()");
267  free_spe_context(spe);
268  /* we mask most errors, but leave ENODEV, etc */
269  switch (errno_saved) {
270  case ENOTSUP:
271  case EEXIST:
272  case EINVAL:
273  case EBUSY:
274  case EPERM:
275  case ENODEV:
276  errno = errno_saved; /* restore errno */
277  break;
278  default:
279  errno = EFAULT;
280  break;
281  }
282  return NULL;
283  }
284 
285  priv->flags = flags;
286 
287  /* Map the required areas into process memory */
288  priv->mem_mmap_base = mapfileat(priv->fd_spe_dir, "mem", LS_SIZE);
289  if (priv->mem_mmap_base == MAP_FAILED) {
290  DEBUG_PRINTF("ERROR: Could not map SPE memory.\n");
291  free_spe_context(spe);
292  errno = ENOMEM;
293  return NULL;
294  }
295 
296  if (flags & SPE_MAP_PS) {
297  /* It's possible to map the entire problem state area with
298  * one mmap - try this first */
299  priv->psmap_mmap_base = mapfileat(priv->fd_spe_dir,
300  "psmap", PSMAP_SIZE);
301 
302  if (priv->psmap_mmap_base != MAP_FAILED) {
303  priv->mssync_mmap_base =
305  priv->mfc_mmap_base =
306  priv->psmap_mmap_base + MFC_OFFSET;
307  priv->cntl_mmap_base =
309  priv->signal1_mmap_base =
311  priv->signal2_mmap_base =
313 
314  } else {
315  /* map each region separately */
316  priv->mfc_mmap_base =
317  mapfileat(priv->fd_spe_dir, "mfc", MFC_SIZE);
318  priv->mssync_mmap_base =
319  mapfileat(priv->fd_spe_dir, "mss", MSS_SIZE);
320  priv->cntl_mmap_base =
321  mapfileat(priv->fd_spe_dir, "cntl", CNTL_SIZE);
322  priv->signal1_mmap_base =
323  mapfileat(priv->fd_spe_dir, "signal1",
324  SIGNAL_SIZE);
325  priv->signal2_mmap_base =
326  mapfileat(priv->fd_spe_dir, "signal2",
327  SIGNAL_SIZE);
328 
329  if (priv->mfc_mmap_base == MAP_FAILED ||
330  priv->cntl_mmap_base == MAP_FAILED ||
331  priv->signal1_mmap_base == MAP_FAILED ||
332  priv->signal2_mmap_base == MAP_FAILED) {
333  DEBUG_PRINTF("ERROR: Could not map SPE "
334  "PS memory.\n");
335  free_spe_context(spe);
336  errno = ENOMEM;
337  return NULL;
338  }
339  }
340  }
341 
343  if (setsignotify(priv->fd_spe_dir, "signal1_type")) {
344  DEBUG_PRINTF("ERROR: Could not open SPE "
345  "signal1_type file.\n");
346  free_spe_context(spe);
347  errno = EFAULT;
348  return NULL;
349  }
350  }
351 
353  if (setsignotify(priv->fd_spe_dir, "signal2_type")) {
354  DEBUG_PRINTF("ERROR: Could not open SPE "
355  "signal2_type file.\n");
356  free_spe_context(spe);
357  errno = EFAULT;
358  return NULL;
359  }
360  }
361 
362  return spe;
363 }

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

419 {
420  int ret = free_spe_context(spe);
421 
423 
424  return ret;
425 }

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

92 {
93  pthread_mutex_lock(&spe->base_private->fd_lock[fdesc]);
94 }
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().

97 {
98  pthread_mutex_unlock(&spe->base_private->fd_lock[fdesc]);
99 }
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.

377 {
378  char pathname[256];
379  struct spe_gang_context_base_priv *pgctx = NULL;
380  struct spe_gang_context *gctx = NULL;
381 
382  gctx = malloc(sizeof(*gctx));
383  if (!gctx) {
384  DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
385  return NULL;
386  }
387  memset(gctx, 0, sizeof(*gctx));
388 
389  pgctx = malloc(sizeof(*pgctx));
390  if (!pgctx) {
391  DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
392  free(gctx);
393  return NULL;
394  }
395  memset(pgctx, 0, sizeof(*pgctx));
396 
397  gctx->base_private = pgctx;
398 
399  sprintf(gctx->base_private->gangname, "gang-%i-%lu", getpid(),
400  (unsigned long)gctx);
401  sprintf(pathname, "/spu/%s", gctx->base_private->gangname);
402 
403  gctx->base_private->fd_gang_dir = spu_create(pathname, SPU_CREATE_GANG,
404  S_IRUSR | S_IWUSR | S_IXUSR);
405 
406  if (gctx->base_private->fd_gang_dir < 0) {
407  DEBUG_PRINTF("ERROR: Could not create Gang %s\n", pathname);
408  free_spe_gang_context(gctx);
409  errno = EFAULT;
410  return NULL;
411  }
412 
413  gctx->base_private->flags = flags;
414 
415  return gctx;
416 }
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.

428 {
429  return free_spe_gang_context(gctx);
430 }
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().

102 {
103  if (!locked)
104  _base_spe_context_lock(spe, fdesc);
105 
106  /* already open? */
107  if (spe->base_private->spe_fds_array[fdesc] != -1) {
108  spe->base_private->spe_fds_refcount[fdesc]++;
109  } else {
110  spe->base_private->spe_fds_array[fdesc] =
111  openat(spe->base_private->fd_spe_dir,
112  spe_fd_attr[fdesc].name,
113  spe_fd_attr[fdesc].mode);
114 
115  if (spe->base_private->spe_fds_array[(int)fdesc] > 0)
116  spe->base_private->spe_fds_refcount[(int)fdesc]++;
117  }
118 
119  if (!locked)
120  _base_spe_context_unlock(spe, fdesc);
121 
122  return spe->base_private->spe_fds_array[(int)fdesc];
123 }

Here is the call graph for this function: