[Cbe-oss-dev] [PATCH 3/3] libspe: add image open library
Dirk Herrendoerfer
d.herrendoerfer at de.ibm.com
Thu Jul 16 23:38:03 EST 2009
Patch to add spe_image_open_library function and to change
spe_image_close
enabling loading an SPE executable image from a dynamic shared object
library.
This includes a testimageopenlibrary test case along with building and
using
the libtest.so dynamic shared object library. This patch includes
enhanced
documentation of these functions. Also the Ada interface definition was
extended, but not tested.
Signed-off-by: Brian Watt <bwatt at us.ibm.com>
Acked-by: Dirk Herrendoerfer <d.herrendoerfer [at] de [dot] ibm [dot]
com>
diff -uprN libspe2.orig/ada/libspe2.ads libspe2.add_image_open_library/
ada/libspe2.ads
--- libspe2.orig/ada/libspe2.ads 2009-06-25 15:11:41.000000000 -0500
+++ libspe2.add_image_open_library/ada/libspe2.ads 2009-06-23
16:50:59.000000000 -0500
@@ -69,6 +69,15 @@ package libspe2 is
pragma Import (C, spe_image_open, "spe_image_open");
--
+-- spe_image_open_library
+--
+ function spe_image_open_library
+ (library : char_array;
+ entry : char_array)
+ return spe_program_handle_t;
+ pragma Import (C, spe_image_open_library, "spe_image_open_library");
+
+--
-- spe_image_close
--
function spe_image_close
diff -uprN libspe2.orig/libspe2.c libspe2.add_image_open_library/
libspe2.c
--- libspe2.orig/libspe2.c 2009-06-25 15:22:26.000000000 -0500
+++ libspe2.add_image_open_library/libspe2.c 2009-06-23
16:51:02.000000000 -0500
@@ -132,6 +132,15 @@ spe_program_handle_t * spe_image_open (c
}
/*
+ * spe_image_open_library
+ */
+
+spe_program_handle_t * spe_image_open_library (const char *library,
const char *entry)
+{
+ return _base_spe_image_open_library(library, entry);
+}
+
+/*
* spe_image_close
*/
diff -uprN libspe2.orig/libspe2.h libspe2.add_image_open_library/
libspe2.h
--- libspe2.orig/libspe2.h 2009-06-25 15:18:11.000000000 -0500
+++ libspe2.add_image_open_library/libspe2.h 2009-06-23
16:51:02.000000000 -0500
@@ -85,6 +85,11 @@ int spe_gang_context_destroy (spe_gang_c
spe_program_handle_t * spe_image_open (const char *filename);
/*
+ * spe_image_open_library
+ */
+spe_program_handle_t * spe_image_open_library (const char *library,
const char *entry);
+
+/*
* spe_image_close
*/
int spe_image_close (spe_program_handle_t *program);
diff -uprN libspe2.orig/Makefile libspe2.add_image_open_library/Makefile
--- libspe2.orig/Makefile 2009-06-25 15:52:51.000000000 -0500
+++ libspe2.add_image_open_library/Makefile 2009-06-26
12:20:20.000000000 -0500
@@ -107,7 +107,7 @@ libspe2.pc: Makefile $(TOP)/libspe2.pc.i
@mv $@.tmp $@
$(libspe2_SO): $(libspe2_OBJS) base-all event-all libspe2.pc
- $(CC) $(CFLAGS) -shared -o $@ $(libspe2_OBJS) spebase/*.o speevent/
*.o -lrt -lpthread -Wl,--soname=${libspe2_SONAME}
+ $(CC) $(CFLAGS) -shared -o $@ $(libspe2_OBJS) spebase/*.o speevent/
*.o -lrt -lpthread -ldl -Wl,--soname=${libspe2_SONAME}
$(libspe2_A): $(libspe2_OBJS) base-all event-all
$(CROSS)ar -r $(libspe2_A) $(libspe2_OBJS) spebase/*.o speevent/
*.o $(libspe2_OBJS)
diff -uprN libspe2.orig/spebase/image.c libspe2.add_image_open_library/
spebase/image.c
--- libspe2.orig/spebase/image.c 2009-06-25 15:17:03.000000000 -0500
+++ libspe2.add_image_open_library/spebase/image.c 2009-06-25
17:33:14.000000000 -0500
@@ -19,6 +19,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
@@ -26,12 +27,23 @@
#include <unistd.h>
+#include <dlfcn.h>
+
#include "elf_loader.h"
#include "spebase.h"
+typedef enum _SPE_IMAGE_TYPE {
+ SPE_IMAGE_TYPE_FILE = 0,
+ SPE_IMAGE_TYPE_LIB = 1,
+} SPE_IMAGE_TYPE;
+
struct image_handle {
spe_program_handle_t speh;
- unsigned int map_size;
+ SPE_IMAGE_TYPE image_type;
+ union {
+ unsigned int map_size;
+ void *lib_handle;
+ };
};
spe_program_handle_t *_base_spe_image_open(const char *filename)
@@ -49,6 +61,7 @@ spe_program_handle_t *_base_spe_image_op
ret->speh.elf_image = MAP_FAILED;
ret->speh.handle_size = sizeof(spe_program_handle_t);
ret->speh.toe_shadow = NULL;
+ ret->image_type = SPE_IMAGE_TYPE_FILE;
binfd = open(filename, O_RDONLY);
if (binfd < 0)
@@ -96,6 +109,69 @@ ret_err:
return NULL;
}
+spe_program_handle_t *_base_spe_image_open_library(const char
*library, const char *entry)
+{
+ /* allocate an extra integer in the spe handle to keep the mapped
size information */
+ struct image_handle *ret;
+ spe_program_handle_t *tmp;
+
+ ret = (struct image_handle *)malloc(sizeof(struct image_handle));
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ ret->speh.elf_image = NULL;
+ ret->speh.handle_size = sizeof(spe_program_handle_t);
+ ret->speh.toe_shadow = NULL;
+ ret->image_type = SPE_IMAGE_TYPE_LIB;
+
+ /* load the library */
+ dlerror(); // purge previous error
+ ret->lib_handle = dlopen(library, RTLD_NOW | RTLD_GLOBAL);
+ if (ret->lib_handle == NULL) {
+ DEBUG_PRINTF("dlopen failed: %s\n",dlerror());
+ errno=ELIBACC;
+ goto ret_err;
+ }
+
+ /* find the executable symbol in the library */
+ tmp = (spe_program_handle_t *)dlsym(ret->lib_handle, entry);
+ if (tmp == NULL) {
+ DEBUG_PRINTF("dlsym failed: %s\n",dlerror());
+ errno=ENOENT;
+ goto ret_err;
+ }
+
+ /* Sanity: handle_sizes must match */
+ if (ret->speh.handle_size != tmp->handle_size) {
+ errno=EINVAL;
+ goto ret_err;
+ }
+
+ /* copy existing spe_program_handle_t structure members from the
loaded code to the malloc'ed space */
+ ret->speh.elf_image = tmp->elf_image;
+ ret->speh.toe_shadow = tmp->toe_shadow;
+
+ /*Verify that this is a valid SPE ELF object */
+ if ((_base_spe_verify_spe_elf_image((spe_program_handle_t *) ret)) !
= 0) {
+ goto ret_err;
+ }
+
+ if (_base_spe_toe_ear(&ret->speh))
+ goto ret_err;
+
+ /* ok */
+ return (spe_program_handle_t *) ret;
+
+ /* err & cleanup */
+ret_err:
+ if (ret->lib_handle != NULL) {
+ dlclose(ret->lib_handle);
+ }
+ free(ret);
+ return NULL;
+}
+
int _base_spe_image_close(spe_program_handle_t *handle)
{
int ret = 0;
@@ -108,15 +184,39 @@ int _base_spe_image_close(spe_program_ha
ih = (struct image_handle *)handle;
- if (!ih->speh.elf_image || !ih->map_size) {
+ if (!ih->speh.elf_image) {
errno = EINVAL;
return -1;
}
-
+
if (ih->speh.toe_shadow)
free(ih->speh.toe_shadow);
- ret = munmap(ih->speh.elf_image, ih->map_size );
+ switch(ih->image_type) {
+ case SPE_IMAGE_TYPE_FILE:
+ if (!ih->map_size) {
+ errno = EINVAL;
+ return -1;
+ }
+ ret = munmap(ih->speh.elf_image, ih->map_size );
+ break;
+ case SPE_IMAGE_TYPE_LIB:
+ if (!ih->lib_handle) {
+ errno = EINVAL;
+ return -1;
+ }
+ dlerror(); // purge previous error
+ if (dlclose(ih->lib_handle) != 0) {
+ DEBUG_PRINTF("dlclose failed: %s\n",dlerror());
+ return -1;
+ }
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ break;
+ }
+
free(handle);
return ret;
diff -uprN libspe2.orig/spebase/Makefile
libspe2.add_image_open_library/spebase/Makefile
--- libspe2.orig/spebase/Makefile 2008-11-12 16:32:03.000000000 -0600
+++ libspe2.add_image_open_library/spebase/Makefile 2009-06-26
12:20:19.000000000 -0500
@@ -51,7 +51,7 @@ clean:
rm -rf $(libspebase_A) $(libspebase_OBJS) $(libspebase_SO)
$(libspebase_SO): $(libspebase_OBJS)
- $(CC) $(CFLAGS) -shared -o $@ $^ -lrt -lpthread -Wl,--soname=$
{libspebase_SONAME}
+ $(CC) $(CFLAGS) -shared -o $@ $^ -lrt -lpthread -ldl -Wl,--soname=$
{libspebase_SONAME}
$(libspebase_A): $(libspebase_OBJS)
$(CROSS)ar -r $(libspebase_A) $(libspebase_OBJS)
diff -uprN libspe2.orig/spebase/spebase.h
libspe2.add_image_open_library/spebase/spebase.h
--- libspe2.orig/spebase/spebase.h 2009-06-25 17:30:22.000000000 -0500
+++ libspe2.add_image_open_library/spebase/spebase.h 2009-06-26
15:16:05.000000000 -0500
@@ -28,6 +28,7 @@ extern "C"
#endif
#include <pthread.h>
+#include <stdio.h>
#include "libspe2-types.h"
@@ -257,21 +258,26 @@ extern int _base_spe_context_run(spe_con
unsigned int runflags, void *argp, void *envp, spe_stop_info_t
*stopinfo);
/**
- * _base_spe_image_close unmaps an SPE ELF object that was previously
mapped using
- * spe_image_open.
- * @param handle handle to open file
+ * _base_spe_image_close Closes an SPE ELF object that was previously
opened using
+ * spe_image_open or spe_image_open_library. For spe_image_open the
image is unmapped
+ * and closed. For spe_image_open_library the dynamic shared object
library is closed.
*
- * @retval 0 On success, spe_close_image returns 0.
+ * @param handle A valid address of an SPE program.
+ *
+ * @retval 0 On success, spe_image_close returns 0.
* @retval -1 On failure, -1 is returned and errno is set
appropriately.\n
* Possible values for errno:\n
- * EINVAL From spe_close_image, this indicates that the file,
specified by
- * filename, was not previously mapped by a call to spe_image_open.
+ * EINVAL The specified address of the SPE program is invalid.
+ * A number of other errno values could be returned by the munmap(2)
close(2),
+ * or dlclose(2) system calls which may be utilized by the
spe_image_close function.
+ *
+ * @sa spe_image_open, spe_image_open_library
*/
extern int _base_spe_image_close(spe_program_handle_t *handle);
/**
* _base_spe_image_open maps an SPE ELF executable indicated by
filename into system
- * memory and returns the mapped address appropriate for use by the
spe_create_thread
+ * memory and returns the mapped address appropriate for use by the
spe_program_load
* API. It is often more convenient/appropriate to use the loading
methodologies
* where SPE ELF objects are converted to PPE static or shared
libraries with
* symbols which point to the SPE ELF objects after these special
libraries are
@@ -297,11 +303,44 @@ extern int _base_spe_image_close(spe_pro
* A number of other errno values could be returned by the open(2),
fstat(2),
* mmap(2), munmap(2), or close(2) system calls which may be
utilized by the
* spe_image_open or spe_image_close functions.
- * @sa spe_create_thread
+ *
+ * @sa spe_image_open_library, spe_program_load, spe_image_close
*/
extern spe_program_handle_t *_base_spe_image_open(const char
*filename);
/**
+ * _base_spe_image_open_library opens a PPE dynamic shared object
library
+ * specified by library and loads it into system memory. It then
searches for the
+ * entry as a symbol within this library. The result is a pointer to
an SPE
+ * program handle which can then be used with spe_program_load to
load this SPE main
+ * program into the local store of an SPE before running it with
spe_context_run.
+ *
+ * The image_library is a PPE shared object library containing any
number of PPE
+ * object files that were created as the result of the ppu_embedspu
script.
+ *
+ * @param library Specifies a string pointer that is the library name
to be
+ * dynamically loaded into system memory. If the pointer is NULL,
then the
+ * standard dlopen conventions are followed as described in its man-
page.
+ * @param entry Specifies the name of an SPE ELF executable that is
in the
+ * library. This symbol is the name specified in the ppu-embedspu
command.
+ *
+ * @return On success, a non-null handle to the SPE ELF object is
returned.
+ * On failure, NULL is returned and errno is set to indicate the error.
+ * Possible values for errno include:\n
+ * ELIBACC The library could not be opened.\n
+ * ENOENT The entry symbol could not be found in the library.\n
+ * EFAULT The library or entry parameter points to an address that
was not
+ * contained in the calling process`s address space.
+ *
+ * A number of other errno values could be returned by the dlopen(2),
+ * and dlsym(2) system calls which may be utilized by the
+ * spe_image_open_library function.
+ *
+ * @sa spe_image_open, spe_image_close
+ */
+extern spe_program_handle_t *_base_spe_image_open_library(const char
*library, const char *entry);
+
+/**
* The _base_spe_mfcio_put function places a put DMA command on the
proxy command queue
* of the SPE thread specified by speid. The put command transfers
size bytes of
* data starting at the local store address specified by ls to the
effective
diff -uprN libspe2.orig/tests/libspe2.basic/Makefile
libspe2.add_image_open_library/tests/libspe2.basic/Makefile
--- libspe2.orig/tests/libspe2.basic/Makefile 2009-06-25
15:21:37.000000000 -0500
+++ libspe2.add_image_open_library/tests/libspe2.basic/Makefile
2009-06-24 12:43:27.000000000 -0500
@@ -33,10 +33,14 @@ main_progs = \
testhandler.elf \
testevent1.elf \
testevent2.elf \
- testmbox.elf
+ testmbox.elf \
+ testimageopenlibrary.elf
ppu_progs =
+ppu_libs = \
+ libtest.so
+
spu_progs = \
helloworld.spu.elf \
hellointr.spu.elf \
@@ -47,3 +51,6 @@ extra_main_progs = \
testmap1.elf
include $(TEST_TOP)/make.rules
+
+libtest.so: helloworld.embed.o
+ $(CC) -shared $(filter %.o,$^) -o $@ $(LDFLAGS)
diff -uprN libspe2.orig/tests/libspe2.basic/testimageopenlibrary.c
libspe2.add_image_open_library/tests/libspe2.basic/
testimageopenlibrary.c
--- libspe2.orig/tests/libspe2.basic/testimageopenlibrary.c 1969-12-31
18:00:00.000000000 -0600
+++ libspe2.add_image_open_library/tests/libspe2.basic/
testimageopenlibrary.c 2009-06-24 16:43:57.000000000 -0500
@@ -0,0 +1,40 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "libspe2.h"
+
+int main(void)
+{
+ spe_context_ptr_t ctx;
+ int flags = 0;
+ unsigned int entry = SPE_DEFAULT_ENTRY;
+ void * argp = NULL;
+ void * envp = NULL;
+ spe_program_handle_t * program;
+ spe_stop_info_t stop_info;
+ int rc;
+
+ program = spe_image_open_library("./libtest.so","helloworld");
+ if (!program) {
+ perror("spe_image_open_library");
+ return -1;
+ }
+
+ ctx = spe_context_create(flags, NULL);
+ if (ctx == NULL) {
+ perror("spe_context_create");
+ return -2;
+ }
+ if (spe_program_load(ctx, program)) {
+ perror("spe_program_load");
+ return -3;
+ }
+ rc = spe_context_run(ctx, &entry, 0, argp, envp, &stop_info);
+ if (rc < 0)
+ perror("spe_context_run");
+
+ spe_context_destroy(ctx);
+
+ return 0;
+}
+
diff -uprN libspe2.orig/tests/make.rules
libspe2.add_image_open_library/tests/make.rules
--- libspe2.orig/tests/make.rules 2009-06-25 15:17:34.000000000 -0500
+++ libspe2.add_image_open_library/tests/make.rules 2009-06-24
12:48:25.000000000 -0500
@@ -29,7 +29,7 @@ spu_elfs = $(filter %.elf,$(spu_progs))
.PHONY: all check clean distclean $(checks)
-all: $(main_progs) $(extra_main_progs) $(ppu_progs) $(spu_progs)
+all: $(ppu_libs) $(main_progs) $(extra_main_progs) $(ppu_progs) $
(spu_progs)
check:
@passed=""; \
@@ -56,7 +56,7 @@ $(checks): check-%: %
fi
clean:
- -$(RM) *.elf *.o *.tmp `find . -maxdepth 1 -type l`
+ -$(RM) *.elf *.o *.tmp *.so `find . -maxdepth 1 -type l`
distclean: clean
-$(RM) *~
More information about the cbe-oss-dev
mailing list