Added function bodies for open, close, read, and write, as well as supporting functio...
authorPaul Pearce <pearce@eecs.berkeley.edu>
Wed, 27 May 2009 03:16:08 +0000 (20:16 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Fri, 5 Jun 2009 00:56:28 +0000 (17:56 -0700)
Filled in the function bodies, as well as creating send_message(), write_to_channel(), and read_from_channel() to parlib.c.
Also added supporting macros to parlib.h, as well as the new prototypes for the new functions.

user/parlib/inc/parlib.h
user/parlib/src/parlib.c

index df38511..c1951b9 100644 (file)
@@ -9,6 +9,64 @@
 #undef errno
 extern int errno;
 
+#define OPEN_ID                0
+#define CLOSE_ID       1
+#define READ_ID                2
+#define WRITE_ID       3
+#define LINK_ID                4
+#define UNLINK_ID      5
+#define LSEEK_ID       6
+#define FSTAT_ID       7
+#define ISATTY_ID      8
+#define STAT_ID                9
+#define NUM_CALLS      10
+
+
+// Fixed size of the client->server msgs for the various calls.
+#define OPEN_MESSAGE_FIXED_SIZE        sizeof(syscall_id) + 3*sizeof(int)
+#define CLOSE_MESSAGE_FIXED_SIZE       sizeof(syscall_id) + sizeof(int)
+#define READ_MESSAGE_FIXED_SIZE        sizeof(syscall_id) + 2*sizeof(int)
+#define WRITE_MESSAGE_FIXED_SIZE       sizeof(syscall_id) + 2*sizeof(int)
+#define LSEEK_MESSAGE_FIXED_SIZE       sizeof(syscall_id) + 3*sizeof(int)
+#define ISATTY_MESSAGE_FIXED_SIZE      sizeof(syscall_id) + sizeof(int)
+#define LINK_MESSAGE_FIXED_SIZE        sizeof(syscall_id) + 2*sizeof(int)
+#define UNLINK_MESSAGE_FIXED_SIZE      sizeof(syscall_id) + sizeof(int)
+#define FSTAT_MESSAGE_FIXED_SIZE       sizeof(syscall_id) + sizeof(int)
+#define STAT_MESSAGE_FIXED_SIZE        sizeof(syscall_id) + sizeof(int)
+
+// What is the max number of arguments (besides the syscall_id) we can have.
+// This should be the max of the above sizes.
+// This exists so we can  allocate a fixed amount of memory to process all incoming msgs
+// TODO: This makes the implicit assumption when referenced in server.c that each argument is of type int.
+//             If we change the above defs to no longer be sizeof(int) this will break in server.c
+#define MAX_FIXED_ARG_COUNT 3
+
+// Fixed server-> respponse msg sizes.
+#define OPEN_RETURN_MESSAGE_FIXED_SIZE                 sizeof(int)
+#define CLOSE_RETURN_MESSAGE_FIXED_SIZE        sizeof(int)
+#define READ_RETURN_MESSAGE_FIXED_SIZE                 sizeof(int)
+#define WRITE_RETURN_MESSAGE_FIXED_SIZE        sizeof(int)
+#define LSEEK_RETURN_MESSAGE_FIXED_SIZE        sizeof(int)
+#define ISATTY_RETURN_MESSAGE_FIXED_SIZE       sizeof(int)
+#define UNLINK_RETURN_MESSAGE_FIXED_SIZE       sizeof(int)
+#define LINK_RETURN_MESSAGE_FIXED_SIZE                 sizeof(int)
+#define STAT_RETURN_MESSAGE_FIXED_SIZE                 sizeof(int) + sizeof(struct stat)
+#define FSTAT_RETURN_MESSAGE_FIXED_SIZE        sizeof(int) + sizeof(struct stat)
+
+// New errno we want to define if a channel error occurs
+// Not yet fully implimented
+#define ECHANNEL -999
+
+// Value to send across the channel as a function return value in the event of server side termination
+// Note yet fully implimented
+#define CONNECTION_TERMINATED -2
+
+// Should refactor this next typedef. Just leave it as type int.
+typedef int syscall_id;
+
+// Replace with uint8?
+typedef char byte;
+
 /* _exit()
  * Exit a program without cleaning up files. 
  * If your system doesn't provide this, it is best to avoid linking 
@@ -95,6 +153,13 @@ int open(const char *name, int flags, int mode);
  */
 int read(int file, char *ptr, int len);
 
+/* Read len bytes from the given channel to the buffer.
+ * If peek is 0, will wait indefinitely until that much data is read.
+ * If peek is 1, if no data is available, will return immediately.
+ *             However once some data is available, it will block until the entire amount is available.
+ */
+int read_from_channel(byte * buf, int len, int peek);
+
 /* sbrk()
  * Increase program data space. 
  * As malloc and related functions depend on this, it is 
@@ -104,6 +169,12 @@ int read(int file, char *ptr, int len);
  */
 caddr_t sbrk(int incr);
 
+/* send_message()
+ * Write the message defined in buffer out across the channel, and wait for a response.
+ * Caller is responsible for management of both the buffer passed in and the buffer ptr returned.
+ */
+byte *send_message(byte *message, int len);
+
 /* stat()
  * Status of a file (by name). 
  * Minimal implementation.
@@ -130,15 +201,12 @@ int wait(int *status);
 
 /* write()
  * Write to a file. 
- * libc subroutines will use this system routine for output 
- * to all files, including stdout—so if you need to generate 
- * any output, for example to a serial port for debugging, 
- * you should make your minimal write capable of doing this. 
- * The following minimal implementation is an incomplete example; 
- * it relies on a outbyte subroutine (not shown; typically, you must 
- * write this in assembler from examples provided by your hardware 
- * manufacturer) to actually perform the output.
  */
 int write(int file, char *ptr, int len);
 
+/* write_to_channel()
+ * Send a message out over the channel, defined by msg, of length len
+ */
+int write_to_channel(byte * msg, int len);
+
 #endif //_NEWLIB_LIBC_WRAPPERS_H_
index f3336fc..f2bd26c 100644 (file)
@@ -28,11 +28,38 @@ void _exit()
     
 /* close()
  * Close a file. 
- * Minimal implementation.
  */
 int close(int file) 
 {
-       return -1;
+       // Allocate a new buffer of proper size
+       byte *out_msg = malloc(CLOSE_MESSAGE_FIXED_SIZE);
+       if(out_msg == NULL)
+               return -1;
+
+       byte *out_msg_pos = out_msg;
+
+       // Fill the buffer
+       *((syscall_id *)out_msg_pos) = CLOSE_ID;
+       out_msg_pos += sizeof(syscall_id);
+
+       *((int*)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+
+
+       // Send message
+       byte *result = send_message(out_msg, CLOSE_MESSAGE_FIXED_SIZE);
+
+       free(out_msg);
+
+       if (result != NULL) {
+               // Read result
+               int return_val;
+               return_val = *((int *) result);
+               free(result);
+               return return_val;
+       } else {
+               return -1;
+       }
 }
 
 /* execve()
@@ -130,20 +157,121 @@ int __sseek64(int file, int ptr, int dir)
 
 /* open()
  * Open a file. 
- * Minimal implementation.
  */
 int open(const char *name, int flags, int mode) 
 {
-       return -1;
+       int s_len = strlen(name) + 1; // Null terminator
+       int out_msg_len = OPEN_MESSAGE_FIXED_SIZE + s_len;
+
+       // Allocate a new buffer of proper size
+       byte *out_msg = malloc(out_msg_len);
+       byte *out_msg_pos = out_msg;
+
+       if (out_msg == NULL)
+               return -1;
+
+       // Fill the buffer
+       *((syscall_id*)out_msg_pos) = OPEN_ID;
+       out_msg_pos += sizeof(syscall_id);
+
+       *((int*)out_msg_pos) = flags;
+       out_msg_pos += sizeof(int);
+
+       *((int*)out_msg_pos) = mode;
+       out_msg_pos += sizeof(int);
+
+       *((int*)out_msg_pos) = s_len;
+       out_msg_pos += sizeof(int);
+
+       memcpy(out_msg_pos, name, s_len);
+
+       // Send message
+       byte *result = send_message(out_msg, out_msg_len);
+
+       free(out_msg);
+
+       // Read result
+       int return_val;
+
+       if (result != NULL) {
+               return_val = *((int *)result);
+               free(result);
+       } else {
+               return_val = -1;
+       }
+
+       return return_val;
 }
 
 /* read()
  * Read from a file. 
- * Minimal implementation.
  */
 int read(int file, char *ptr, int len) 
 {
-       return 0;
+       // Allocate a new buffer of proper size
+       byte *out_msg = (byte*)malloc(READ_MESSAGE_FIXED_SIZE);
+       if (out_msg == NULL)
+               return -1;
+
+       byte *out_msg_pos = out_msg;
+
+       // Fill the buffer
+       *((syscall_id*)out_msg_pos) = READ_ID;
+       out_msg_pos += sizeof(syscall_id);
+
+       *((int *)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+
+       *((int *)out_msg_pos) = len;
+       out_msg_pos += sizeof(int);
+
+       // Send message
+       byte *result = send_message(out_msg, READ_MESSAGE_FIXED_SIZE);
+
+       free(out_msg);
+
+       // Read result
+       int return_val;
+
+       if (result != NULL) {
+               return_val = *((int *)result);
+               memcpy(ptr, ((int *)result) + 1, return_val);
+               free(result);
+       } else {
+               return_val = -1;
+       }
+
+       return return_val;
+}
+
+/* Read len bytes from the given channel to the buffer.
+ * If peek is 0, will wait indefinitely until that much data is read.
+ * If peek is 1, if no data is available, will return immediately.
+ *             However once some data is available, it will block until the entire amount is available.
+ */
+int read_from_channel(byte * buf, int len, int peek)
+{
+       // TODO: NEED TO IMPLIMENT A TIMEOUT
+       //                      Also, watch out for CONNECTION TERMINATED
+       // TODO: Add a #define for peek / no peek. Don't know why I didnt do this from the start?
+       int total_read = 0;
+
+       int just_read = sys_serial_read(buf, len);
+
+
+       if (just_read < 0) return just_read;
+       if (just_read == 0 && peek) return just_read;
+
+       total_read += just_read;
+
+       while (total_read != len) {
+               just_read = read(buf + total_read, len - total_read);
+
+               if (just_read == -1) return -1;
+               total_read += just_read;
+       }
+
+       return total_read;
 }
 
 /* sbrk()
@@ -176,6 +304,121 @@ caddr_t sbrk(int incr)
        return (void*)-1;
 }
 
+/* send_message()
+ * Write the message defined in buffer out across the channel, and wait for a response.
+ * Caller is responsible for management of both the buffer passed in and the buffer ptr returned.
+ */
+byte *send_message(byte *message, int len)
+{
+
+       syscall_id this_call_id = *((syscall_id*)message);
+
+       if (write_to_channel(message, len) != len)
+               return NULL;
+
+       int response_value;
+
+       // Pull the response from the server out of the channel.
+       if (read_from_channel((char*)&response_value, sizeof(int), 0) == -1) return NULL;
+
+       byte* return_msg;
+
+       // TODO: Make these sizes an array we index into, and only have this code once.
+       // TODO: Will have a flag that tells us we have a variable length response (right now only for read case)
+       // TODO: Default clause with error handling.
+       switch (this_call_id) {
+               case OPEN_ID:
+                       if ((return_msg = (byte*)malloc(OPEN_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
+                               return NULL;
+
+                       break;
+
+               case CLOSE_ID:
+                       if ((return_msg = (byte*)malloc(CLOSE_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
+                               return NULL;
+
+                       break;
+
+               case READ_ID:
+                       if ((return_msg = (byte*)malloc(READ_RETURN_MESSAGE_FIXED_SIZE + response_value)) == NULL)
+                               return NULL;
+
+
+                       if ((read_from_channel(return_msg + sizeof(int), response_value, 0)) == -1)
+                               return NULL;
+
+                       break;
+
+               case WRITE_ID:
+                       if ((return_msg = (byte*)malloc(WRITE_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
+                               return NULL;
+
+                       break;
+
+
+               case LSEEK_ID:
+                       if ((return_msg = (byte*)malloc(LSEEK_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
+                               return NULL;
+
+                       break;
+
+               case ISATTY_ID:
+                       if ((return_msg = (byte*)malloc(ISATTY_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
+                               return NULL;
+
+                       break;
+
+               case UNLINK_ID:
+                       if ((return_msg = (byte*)malloc(UNLINK_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
+                               return NULL;
+
+
+                       if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int), sizeof(int), 0)) == -1))
+                               return NULL;
+
+                       break;
+
+               case LINK_ID:
+                       if ((return_msg = (byte*)malloc(LINK_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
+                               return NULL;
+
+
+                       if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int), sizeof(int), 0)) == -1))
+                               return NULL;
+
+                       break;
+
+               case FSTAT_ID:
+                       if ((return_msg = (byte*)malloc(FSTAT_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
+                               return NULL;
+
+                       if ((read_from_channel(return_msg + sizeof(int), sizeof(struct stat), 0)) == -1)
+                               return NULL;
+
+                       if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int) + sizeof(struct stat), sizeof(int), 0)) == -1))
+                               return NULL;
+
+                       break;
+
+               case STAT_ID:
+                       if ((return_msg = (byte*)malloc(STAT_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
+                               return NULL;
+
+                       if ((read_from_channel(return_msg + sizeof(int), sizeof(struct stat), 0)) == -1)
+                               return NULL;
+
+                       if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int) + sizeof(struct stat), sizeof(int), 0)) == -1))
+                               return NULL;
+
+                       break;
+       }
+
+       memcpy(return_msg, &response_value, sizeof(int));
+
+       return return_msg;
+}
+
+
 /* stat()
  * Status of a file (by name). 
  * Minimal implementation.
@@ -217,18 +460,51 @@ int wait(int *status)
 
 /* write()
  * Write to a file. 
- * libc subroutines will use this system routine for output 
- * to all files, including stdout—so if you need to generate 
- * any output, for example to a serial port for debugging, 
- * you should make your minimal write capable of doing this. 
- * The following minimal implementation is an incomplete example; 
- * it relies on a outbyte subroutine (not shown; typically, you must 
- * write this in assembler from examples provided by your hardware 
- * manufacturer) to actually perform the output.
- */
-#define outbyte(arg)
+ */
 int write(int file, char *ptr, int len) {
-       return 0;
+       int out_msg_len = WRITE_MESSAGE_FIXED_SIZE + len;
+
+       // Allocate a new buffer of proper size
+       byte *out_msg = malloc(out_msg_len);
+       byte *out_msg_pos = out_msg;
+
+       // Fill the buffer
+       *((syscall_id*)out_msg_pos) = WRITE_ID;
+       out_msg_pos += sizeof(syscall_id);
+
+       *((int*)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+
+       *((int*)out_msg_pos) = len;
+       out_msg_pos += sizeof(int);
+
+       memcpy(out_msg_pos, ptr, len);
+
+       // Send message
+       byte *result = send_message(out_msg, out_msg_len);
+
+       free(out_msg);
+
+       // Read result
+       int return_val;
+
+       if (result != NULL) {
+               return_val = *((int *)result);
+               free(result);
+       } else {
+               return_val = -1;
+       }
+
+       return return_val;
+}
+
+
+/* write_to_channel()
+ * Send a message out over the channel, defined by msg, of length len
+ */
+int write_to_channel(byte * msg, int len)
+{
+       return sys_serial_write((char*)msg, len);
 }
 
 /* __swrite64()