This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
[PATCH RFC] libspe2 add opendir and related functions
- From: Patrick Mansfield <patmans at us dot ibm dot com>
- To: cbe-oss-dev at ozlabs dot org, newlib at sourceware dot org
- Date: Thu, 14 Jun 2007 08:03:37 -0700
- Subject: [PATCH RFC] libspe2 add opendir and related functions
Add libspe assist calls for:
DIR *opendir(const char *name)
int closedir(DIR *dir)
struct dirent *readdir(DIR *dir)
void rewinddir(DIR *dir)
void seekdir(DIR *dir, off_t offset)
off_t telldir(DIR *dir)
These have a similar problem as with the fopen assist call, in that we
have to return a 32 bit value. For 32 bit ppc, just use the ppc DIR
pointer, for 64 bit ppc map to an integer via an array.
Is the SPU dirent OK? POSIX only requires d_ino and d_name.
Any other comments?
Signed-off-by: Patrick Mansfield <patmans@us.ibm.com>
Index: quilt-libspe2/spebase/default_posix1_handler.c
===================================================================
--- quilt-libspe2.orig/spebase/default_posix1_handler.c
+++ quilt-libspe2/spebase/default_posix1_handler.c
@@ -34,6 +34,9 @@
#include <sys/wait.h>
#include <fcntl.h>
#include <linux/limits.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <dirent.h>
#include "default_posix1_handler.h"
#include "handler_utils.h"
@@ -142,6 +145,12 @@ enum {
SPE_POSIX1_TRUNCATE,
SPE_POSIX1_MKSTEMP,
SPE_POSIX1_MKTEMP,
+ SPE_POSIX1_OPENDIR,
+ SPE_POSIX1_CLOSEDIR,
+ SPE_POSIX1_READDIR,
+ SPE_POSIX1_REWINDDIR,
+ SPE_POSIX1_SEEKDIR,
+ SPE_POSIX1_TELLDIR,
SPE_POSIX1_LAST_OPCODE,
};
#define SPE_POSIX1_NR_OPCODES \
@@ -207,6 +216,99 @@ struct spe_compat_timex {
int :32; int :32; int :32; int :32;
};
+struct spe_compat_dirent {
+ uint32_t d_ino;
+ char d_name[256];
+};
+
+#ifdef __powerpc64__
+
+/*
+ * Use an array mapping pointers to integer values, like we do in C99
+ * fopen. SPE_OPENDIR_MAX should probably be OPEN_MAX, but that is very
+ * large (256), especially given that there should not be a lot of
+ * currently opendir's on the SPU.
+ *
+ * Note that newlib or other implementations still have to allocate space
+ * for readdir() results.
+ *
+ * The index zero can't be used, since it is the same as NULL, so it is
+ * unused, and our maximum allowed opendir's is really SPE_OPENDIR_MAX - 1.
+ */
+
+#define SPE_OPENDIR_MAX 17
+static DIR *spe_dir[SPE_OPENDIR_MAX]; /* initialized to zero by default */
+static pthread_mutex_t spe_dir_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static uint32_t spe_mapdir(DIR *dir)
+{
+ int i;
+
+ pthread_mutex_lock(&spe_dir_mutex);
+ /*
+ * 0 can't be used, so start the loop at 1.
+ */
+ for (i = 1; i < SPE_OPENDIR_MAX; i++) {
+ if (spe_dir[i] == NULL) {
+ break;
+ }
+ }
+ if (i >= SPE_OPENDIR_MAX) {
+ i = 0;
+ errno = EMFILE;
+ } else {
+ spe_dir[i] = dir;
+ }
+ pthread_mutex_unlock(&spe_dir_mutex);
+ return i;
+}
+
+static DIR *spe_unmapdir(uint32_t ind)
+{
+ DIR *dir;
+
+ pthread_mutex_lock(&spe_dir_mutex);
+ dir = spe_dir[ind];
+ spe_dir[ind] = NULL;
+ pthread_mutex_unlock(&spe_dir_mutex);
+ return dir;
+}
+
+static DIR *spe_getdir(uint32_t ind)
+{
+ /*
+ * Locking does not help much, since we could lock get a value unlock,
+ * and then have it be unmapped.
+ */
+ return spe_dir[ind];
+}
+
+#else
+/*
+ * Just pass back the 32 bit value in dir or ind.
+ */
+static inline uint32_t spe_mapdir(DIR *dir)
+{
+ return (uint32_t) dir;
+}
+
+static inline DIR *spe_unmapdir(uint32_t ind)
+{
+ return (DIR *) ind;
+}
+
+static inline DIR *spe_getdir(uint32_t ind)
+{
+ return (DIR *) ind;
+}
+#endif
+
+static void spe_copy_dirent(struct spe_compat_dirent *spe_ent,
+ struct dirent *ent)
+{
+ spe_ent->d_ino = ent->d_ino;
+ memcpy(spe_ent->d_name, ent->d_name, sizeof(spe_ent->d_name));
+}
/**
* default_posix1_handler_stat
@@ -1765,6 +1867,178 @@ int default_posix1_handler_mktemp(char *
return 0;
}
+/**
+ * default_posix1_handler_opendir
+ * @ls: base pointer to local store area.
+ * @opdata: POSIX.1 call opcode & data.
+ *
+ * Implement:
+ * DIR *opendir(const char *dirname);
+ */
+int default_posix1_handler_opendir(char *ls, unsigned long opdata)
+{
+ DECL_1_ARGS();
+ DECL_RET();
+ char *name;
+ DIR *dir;
+ int rc;
+
+ DEBUG_PRINTF("%s\n", __func__);
+ name = GET_LS_PTR(arg0->slot[0]);
+ dir = opendir(name);
+ if (dir) {
+ rc = spe_mapdir(dir);
+ if (!rc) {
+ /*
+ * opendir worked but spe_mapdir failed.
+ */
+ closedir(dir);
+ }
+ } else {
+ rc = 0; /* NULL */
+ }
+ PUT_LS_RC(rc, 0, 0, errno);
+ return 0;
+}
+
+/**
+ * default_posix1_handler_closedir
+ * @ls: base pointer to local store area.
+ * @opdata: POSIX.1 call opcode & data.
+ *
+ * Implement:
+ * DIR *closedir(const char *dirname);
+ */
+int default_posix1_handler_closedir(char *ls, unsigned long opdata)
+{
+ DECL_1_ARGS();
+ DECL_RET();
+ DIR *dir;
+ int rc;
+
+ DEBUG_PRINTF("%s\n", __func__);
+ dir = spe_unmapdir(arg0->slot[0]);
+ if (dir) {
+ rc = closedir(dir);
+ } else {
+ rc = -1;
+ errno = EBADF;
+ }
+ PUT_LS_RC(rc, 0, 0, errno);
+ return 0;
+}
+
+/**
+ * default_posix1_handler_readdir
+ * @ls: base pointer to local store area.
+ * @opdata: POSIX.1 call opcode & data, plus a secondary argument pass the
+ * location of the dirent.
+ *
+ * Implement:
+ * struct dirent *readdir(DIR *dir)
+ */
+int default_posix1_handler_readdir(char *ls, unsigned long opdata)
+{
+ DECL_2_ARGS();
+ DECL_RET();
+ DIR *dir;
+ struct dirent *ent;
+ struct spe_compat_dirent *spe_ent;
+ int rc;
+
+ DEBUG_PRINTF("%s\n", __func__);
+ spe_ent = GET_LS_PTR(arg1->slot[0]);
+ dir = spe_getdir(arg0->slot[0]);
+ if (dir) {
+ ent = readdir(dir);
+ if (ent) {
+ spe_copy_dirent(spe_ent, ent);
+ rc = arg1->slot[0]; /* LS address of spe_ent */
+ } else {
+ rc = 0;
+ }
+ } else {
+ rc = 0; /* NULL */
+ errno = EBADF;
+ }
+ PUT_LS_RC(rc, 0, 0, errno);
+ return 0;
+}
+
+/**
+ * default_posix1_handler_rewinddir
+ * @ls: base pointer to local store area.
+ * @opdata: POSIX.1 call opcode & data
+ *
+ * Implement:
+ * void rewinddir(DIR *dir)
+ */
+int default_posix1_handler_rewinddir(char *ls, unsigned long opdata)
+{
+ DECL_1_ARGS();
+ DECL_RET();
+ DIR *dir;
+
+ DEBUG_PRINTF("%s\n", __func__);
+ dir = spe_getdir(arg0->slot[0]);
+ if (dir) {
+ rewinddir(dir);
+ }
+ PUT_LS_RC(0, 0, 0, 0);
+ return 0;
+}
+
+/**
+ * default_posix1_handler_seekdir
+ * @ls: base pointer to local store area.
+ * @opdata: POSIX.1 call opcode & data
+ *
+ * Implement:
+ * void seekdir(DIR *dir)
+ */
+int default_posix1_handler_seekdir(char *ls, unsigned long opdata)
+{
+ DECL_2_ARGS();
+ DECL_RET();
+ DIR *dir;
+ off_t offset;
+
+ DEBUG_PRINTF("%s\n", __func__);
+ offset = arg1->slot[0];
+ dir = spe_getdir(arg0->slot[0]);
+ if (dir) {
+ seekdir(dir, offset);
+ }
+ PUT_LS_RC(0, 0, 0, 0);
+ return 0;
+}
+
+/**
+ * default_posix1_handler_telldir
+ * @ls: base pointer to local store area.
+ * @opdata: POSIX.1 call opcode & data
+ *
+ * Implement:
+ */
+int default_posix1_handler_telldir(char *ls, unsigned long opdata)
+{
+ DECL_1_ARGS();
+ DECL_RET();
+ DIR *dir;
+ int rc;
+
+ DEBUG_PRINTF("%s\n", __func__);
+ dir = spe_getdir(arg0->slot[0]);
+ if (dir) {
+ rc = telldir(dir);
+ } else {
+ rc = -1;
+ errno = EBADF;
+ }
+ PUT_LS_RC(rc, 0, 0, errno);
+ return 0;
+}
+
int (*default_posix1_funcs[SPE_POSIX1_NR_OPCODES]) (char *, unsigned long) = {
[SPE_POSIX1_UNUSED] = NULL,
[SPE_POSIX1_ADJTIMEX] = default_posix1_handler_adjtimex,
@@ -1821,6 +2095,12 @@ int (*default_posix1_funcs[SPE_POSIX1_NR
[SPE_POSIX1_TRUNCATE] = default_posix1_handler_truncate,
[SPE_POSIX1_MKSTEMP] = default_posix1_handler_mkstemp,
[SPE_POSIX1_MKTEMP] = default_posix1_handler_mktemp,
+ [SPE_POSIX1_OPENDIR] = default_posix1_handler_opendir,
+ [SPE_POSIX1_CLOSEDIR] = default_posix1_handler_closedir,
+ [SPE_POSIX1_READDIR] = default_posix1_handler_readdir,
+ [SPE_POSIX1_REWINDDIR] = default_posix1_handler_rewinddir,
+ [SPE_POSIX1_SEEKDIR] = default_posix1_handler_seekdir,
+ [SPE_POSIX1_TELLDIR] = default_posix1_handler_telldir,
};
/**
Index: quilt-libspe2/spebase/default_posix1_handler.h
===================================================================
--- quilt-libspe2.orig/spebase/default_posix1_handler.h
+++ quilt-libspe2/spebase/default_posix1_handler.h
@@ -77,5 +77,11 @@ extern int default_posix1_handler_lockf(
extern int default_posix1_handler_truncate(char *ls, unsigned long args);
extern int default_posix1_handler_mkstemp(char *ls, unsigned long args);
extern int default_posix1_handler_mktemp(char *ls, unsigned long args);
+extern int default_posix1_handler_opendir(char *ls, unsigned long args);
+extern int default_posix1_handler_closedir(char *ls, unsigned long args);
+extern int default_posix1_handler_readdir(char *ls, unsigned long args);
+extern int default_posix1_handler_rewinddir(char *ls, unsigned long args);
+extern int default_posix1_handler_seekdir(char *ls, unsigned long args);
+extern int default_posix1_handler_telldir(char *ls, unsigned long args);
#endif /* __DEFAULT_POSIX1_HANDLER_H__ */