l4-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Making use of string items in the capability system.


From: Matthieu Lemerre
Subject: Re: Making use of string items in the capability system.
Date: Wed, 23 Feb 2005 19:30:22 +0000
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux)

Hi,

Marcus Brinkmann <address@hidden> writes:

>> OK.  What should I do in manage_mt_worker if allocate_string_item_buffers 
>> fails? 
>
> Good catch.  Uhm, this is troublesome.  The current code pretty much
> assumes that the startup of a worker thread can't fail.  I would hate
> to break that assumption.
>
> So, I think the right thing to do is to allocate the buffers in the
> manager thread already, where it at least will know about the failure
> before starting the worker thread.  You need to pass down the
> information somehow to the worker then, in a per-worker structure
> (which can be alloc'ed and then freed by the worker).  This is a bit
> of extra work, but I really think all errors should be catched in the
> manager before starting the worker.
>
> Note that this extra complexity could be saved if we decide to
> allocate the memory on the stack of the worker (in case it is not too
> much).
>
> So, yes, I am afraid this needs to be rearranged a bit to properly
> deal with errors.
>
> BTW, if allocation fails in the manager, it is still not entirely
> clear what should be done!  But at least that's a possibility we have
> to deal with anyway (in case pthread_create fails).  So, at least all
> the problems are in one place.

This new patch solves the problem. Basically, struct worker_info now
contains a generic part and a worker-specific part, and is now alloced
by malloc in the worker thread and freed by the worker thread. 

In the case of asynchronous thread allocation, the worker thread will
just try later if it can't malloc any memory. I don't know if this is
the right thing to do; If we had to, we could get rid of the malloc on
the worker_info by allocating this memory on the manager thread's
stack and wait for the worker thread to "say" that it does not need
this memory anymore.

I also updated the Changelog.

I also re-submit my patches which integrated string item support into
deva and libc because I think that it conflicts with some of these new
changes (and because I changed my additions to libl4 to conform to the
aliasing rules).


Changelog:

libl4/:
2005-02-23  Matthieu Lemerre  <address@hidden>

        * l4/ipc.h (_L4_msg_store_parsed): New function.
        * l4/gnu/ipc.h (l4_msg_store_parsed): Likewise.


libhurd-cap-server/:
2005-02-23  Matthieu Lemerre  <address@hidden>

        * cap-server.h (hurd_cap_bucket_create): Fix signature.

        * bucket-manage-mt.c (struct worker_info): Changed name to
        generic_worker_info.
        (struct worker_info): New structure.
        (free_string_buffers, allocate_string_buffers): New functions.
        (get_msg_buffer, flush_string_buffers): Likewise.
        (manage_mt_worker): Use the new struct worker_info. Accept string
        items. Free struct worker_info.
        (manage_mt_get_next_worker): Allocate a struct worker_info.
        (worker_alloc_async): Likewise.
        (hurd_cap_bucket_manage_mt): Likewise, accept strings item and
        transmit it to the worker thread.

        * bucket-free.c (hurd_cap_bucket_free): Free the string_buf_sizes
        array alloced in hurd_cap_bucket_create.

        * bucket-create.c (MAX_STRING_BUFFERS): New constant.
        Added header files.
        (hurd_cap_bucket_create): Added string_buf_count and
        string_buf_sizes argument. Put them in the bucket.

        * cap-server-intern.h (struct _hurd_cap_bucket): string_buf_count,
        string_buf_sizes: new fields.

deva/:
2005-02-23  Matthieu Lemerre  <address@hidden>

        * deva.c (main): Changed call to hurd_bucket_create.

physmem/:
2005-02-23  Matthieu Lemerre  <address@hidden>

        * physmem.c (main): Changed call to hurd_bucket_create.

task/:
2005-02-23  Matthieu Lemerre  <address@hidden>

        * task.c (main): Changed call to hurd_bucket_create.

ruth/:
2005-02-23  Matthieu Lemerre  <address@hidden>

        * ruth.c (main): Changed call to hurd_bucket_create.


Patch:
diff -rup /home/racin/src/hurd/mainline/darcs/hurd-l4/deva/deva.c 
hurd-l4/deva/deva.c
--- /home/racin/src/hurd/mainline/darcs/hurd-l4/deva/deva.c     2005-02-14 
01:22:17.000000000 +0000
+++ hurd-l4/deva/deva.c 2005-02-23 17:56:54.000000000 +0000
@@ -266,7 +266,7 @@ main (int argc, char *argv[])
   if (err)
     panic ("device_class_init: %i\n", err);
 
-  err = hurd_cap_bucket_create (&bucket);
+  err = hurd_cap_bucket_create (&bucket, 0, NULL);
   if (err)
     panic ("bucket_create: %i\n", err);
 
diff -rup 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/bucket-create.c 
hurd-l4/libhurd-cap-server/bucket-create.c
--- 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/bucket-create.c  
    2005-02-14 01:22:16.000000000 +0000
+++ hurd-l4/libhurd-cap-server/bucket-create.c  2005-02-23 17:56:54.000000000 
+0000
@@ -27,9 +27,13 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <pthread.h>
+#include <string.h>
 
 #include "cap-server-intern.h"
 
+
+#include <l4/message.h>
+#define MAX_STRING_BUFFERS (L4_NUM_BRS - 1)/2
 
 /* Process the task death event for TASK_ID.  */
 static void
@@ -87,12 +91,16 @@ _hurd_cap_client_death (void *hook, hurd
 
 
 /* Create a new bucket and return it in R_BUCKET.  */
-error_t
-hurd_cap_bucket_create (hurd_cap_bucket_t *r_bucket)
+error_t hurd_cap_bucket_create (hurd_cap_bucket_t *r_bucket,
+                               int string_buf_count,
+                               size_t *string_buf_sizes)
 {
   error_t err;
   hurd_cap_bucket_t bucket;
 
+  if (string_buf_count < 0 || string_buf_count > MAX_STRING_BUFFERS)
+    return EINVAL;
+
   bucket = malloc (sizeof (struct _hurd_cap_bucket));
   if (!bucket)
     return errno;
@@ -148,6 +156,22 @@ hurd_cap_bucket_create (hurd_cap_bucket_
      and bucket->worker_alloc_state will be initialized if
      asynchronous worker thread allocation is used.  */
 
+  /* String items management. */
+
+  bucket->string_buf_count = string_buf_count;
+  if (string_buf_count)
+    {
+      bucket->string_buf_sizes = malloc ((string_buf_count)
+                                        * sizeof (size_t));
+      if (!bucket->string_buf_sizes)
+       {
+         err = errno;
+         goto err_string_buf_sizes;
+       }
+      memcpy (bucket->string_buf_sizes, string_buf_sizes,
+             string_buf_count * sizeof (size_t));
+    }
+
   /* Finally, add the notify handler.  */
   bucket->client_death_notify.notify_handler = _hurd_cap_client_death;
   bucket->client_death_notify.hook = bucket;
@@ -158,9 +182,11 @@ hurd_cap_bucket_create (hurd_cap_bucket_
 
 #if 0
   /* Provided here in case more error cases are added.  */
-  hurd_table_destroy (&bucket->clients);
+  free (bucket->string_buf_sizes);
 #endif
-
+  
+ err_string_buf_sizes:
+  hurd_table_destroy (&bucket->clients);
  err_clients:
   pthread_cond_destroy (&bucket->cond);
  err_cond:
diff -rup 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/bucket-free.c 
hurd-l4/libhurd-cap-server/bucket-free.c
--- 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/bucket-free.c    
    2005-02-14 01:22:16.000000000 +0000
+++ hurd-l4/libhurd-cap-server/bucket-free.c    2005-02-23 17:56:54.000000000 
+0000
@@ -42,6 +42,7 @@ hurd_cap_bucket_free (hurd_cap_bucket_t 
   pthread_mutex_destroy (&bucket->lock);
   pthread_mutex_destroy (&bucket->client_cond_lock);
   pthread_cond_destroy (&bucket->client_cond);
+  free (bucket->string_buf_sizes);
   free (bucket);
 }
 
diff -rup 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/bucket-manage-mt.c
 hurd-l4/libhurd-cap-server/bucket-manage-mt.c
--- 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/bucket-manage-mt.c
   2005-02-14 01:22:16.000000000 +0000
+++ hurd-l4/libhurd-cap-server/bucket-manage-mt.c       2005-02-23 
18:01:01.000000000 +0000
@@ -31,6 +31,7 @@
 
 #include <l4.h>
 #include <compiler.h>
+#include <sys/mman.h>
 
 #include "cap-server-intern.h"
 
@@ -64,7 +65,7 @@
 #define _HURD_CAP_MSG_WORKER_ACCEPTED 0
 #define _HURD_CAP_MSG_WORKER_REJECTED 1
 
-struct worker_info
+struct generic_worker_info
 {
   /* The bucket.  */
   hurd_cap_bucket_t bucket;
@@ -76,6 +77,14 @@ struct worker_info
   l4_time_t timeout;
 };
 
+struct worker_info
+{
+  /* Generic information.  */
+  struct generic_worker_info *generic_info;
+
+  /* Allocated string buffers for the worker thread.  */
+  void **string_buffers;
+};
 
 static void
 __attribute__((always_inline))
@@ -118,6 +127,99 @@ lookup_client (hurd_cap_bucket_t bucket,
   return err;
 }
 
+/* Free the NUM first buffers of STRING_BUFFERS, and free
+   STRING_BUFFERS.  */
+void
+free_string_buffers (hurd_cap_bucket_t bucket,
+                    void **string_buffers,
+                    int num)
+{
+  int i=0;
+  size_t *string_buf_sizes = bucket->string_buf_sizes;
+  
+  assert (num <= bucket->string_buf_count);
+  
+  if (!bucket->string_buf_count)
+    return;
+  
+  for (i = 0; i < num; i++)
+    munmap (string_buffers[i], string_buf_sizes[i]);
+
+  free (string_buffers);
+}
+
+
+/* Make R_STRING_BUFFERS point to an array (of size
+   BUCKET->STRING_BUF_COUNT) of pointers to BUCKET->STRING_BUF_SIZES
+   sized memory zones.  */
+error_t
+allocate_string_buffers (hurd_cap_bucket_t bucket,
+                        void ***r_string_buffers)
+{
+  int i=0;
+
+  size_t *string_buf_sizes = bucket->string_buf_sizes;
+  int string_buf_count = bucket->string_buf_count;
+  void **string_buffers;
+
+  if (!string_buf_count)
+    return 0;
+
+  string_buffers = malloc (string_buf_count * sizeof (void *));
+  if (!string_buffers)
+    return errno;
+
+  for (i = 0; i < string_buf_count; i++)
+    {
+      /* We don't need to establish the mapping now, the pager
+        will do it when the string is transferred. */
+      string_buffers[i] = mmap (0, string_buf_sizes[i],
+                               PROT_READ | PROT_WRITE,
+                               MAP_ANONYMOUS | MAP_PRIVATE,
+                               0, 0);
+      if (string_buffers[i] == MAP_FAILED)
+       {
+         error_t saved_errno = errno;
+         free_string_buffers (bucket, string_buffers, i);
+         return saved_errno;
+       }
+    }
+  *r_string_buffers = string_buffers;
+  return 0;
+}
+
+/* Fill MSG_BUFFER with a msg_buffer according to
+   BUCKET->STRING_BUF_SIZES and STRING_BUFFERS.  */
+void
+get_msg_buffer (hurd_cap_bucket_t bucket,
+               void **string_buffers,
+               l4_msg_buffer_t msg_buffer)
+{
+  size_t *string_buf_sizes = bucket->string_buf_sizes;
+  int string_buf_count = bucket->string_buf_count;
+  int i;
+
+  l4_msg_buffer_clear (msg_buffer);
+  
+  for (i = 0; i < string_buf_count; i++)
+    {
+      l4_string_item_t string_item;
+      string_item = l4_string_item (string_buf_sizes[i], string_buffers[i]);
+      l4_msg_buffer_append_simple_rcv_string (msg_buffer, string_item);
+      i++;
+    }
+}
+
+/* Flush the NUM first message buffers.  */
+/* FIXME: flush the underlying memory */
+error_t
+flush_string_buffers (hurd_cap_bucket_t bucket,
+                     void **string_buffers,
+                     int num)
+{
+  assert (num <= bucket->string_buf_count);
+  return 0;
+}
 
 /* Process the message CTX->MSG from thread CTX->FROM in worker thread
    CTX->WORKER of bucket CTX->BUCKET.  Return ECAP_NOREPLY if no reply
@@ -365,14 +467,20 @@ static void *
 manage_mt_worker (void *arg, bool async)
 {
   struct worker_info *info = (struct worker_info *) arg;
-  hurd_cap_bucket_t bucket = info->bucket;
+  struct generic_worker_info *generic_info = info->generic_info;
+  hurd_cap_bucket_t bucket = generic_info->bucket;
   struct _hurd_cap_list_item worker_item;
   _hurd_cap_list_item_t worker = &worker_item;
-  l4_thread_id_t manager = info->manager_tid;
-  l4_time_t timeout = info->timeout;
+  l4_thread_id_t manager = generic_info->manager_tid;
+  l4_time_t timeout = generic_info->timeout;
   l4_thread_id_t from;
   l4_msg_tag_t msg_tag;
   bool current_worker_is_us;
+  void **string_buffers = info->string_buffers;
+  l4_acceptor_t acceptor;
+
+  /* Free the allocated structure the manager has given.  */
+  free (info);
 
   /* Prepare the worker queue item.  [SYNC: As we are always the
      current worker thread when we are started up, we do not add
@@ -382,6 +490,24 @@ manage_mt_worker (void *arg, bool async)
   worker->next = NULL;
   worker->prevp = NULL;
 
+  /* Allocates string items for the thread */
+  if (bucket->string_buf_count)
+    {
+      l4_msg_buffer_t msg_buffer;
+      get_msg_buffer (bucket, string_buffers, msg_buffer);
+      /* We never accept any map or grant items. */      
+      l4_accept_strings (L4_STRING_ITEMS_ACCEPTOR, msg_buffer);
+      acceptor = L4_STRING_ITEMS_ACCEPTOR;
+    }
+  else
+    {
+      acceptor = L4_UNTYPED_WORDS_ACCEPTOR;
+    }
+
+  /* We do not want to block when returning a string item to the
+     client */
+  l4_set_xfer_timeouts (l4_timeouts (L4_ZERO_TIME, L4_NEVER));
+
   if (EXPECT_FALSE (async))
     {
       /* We have to add ourselves to the free list and inform the
@@ -407,6 +533,7 @@ manage_mt_worker (void *arg, bool async)
 
       /* We do not know if we will be the current worker thread or
         not, so we must wait with a timeout.  */
+      l4_accept (acceptor);
       msg_tag = l4_xreceive_timeout (manager, timeout, &from);
     }
   else
@@ -414,11 +541,13 @@ manage_mt_worker (void *arg, bool async)
       /* When we are started up, we are supposed to listen as soon as
         possible to the next incoming message.  When we know we are the
         current worker thread, we do this without a timeout.  */
+      l4_accept (acceptor);
       msg_tag = l4_xreceive (manager, &from);
     }
 
   while (1)
     {
+      int string_item_to_flush = l4_typed_words (msg_tag)/2;
       if (EXPECT_FALSE (l4_ipc_failed (msg_tag)))
        {
          /* Slow path.  */
@@ -446,6 +575,7 @@ manage_mt_worker (void *arg, bool async)
 
          /* If we are the current worker, we should wait here for the
             next message without a timeout.  */
+         l4_accept (acceptor);
          msg_tag = l4_xreceive (manager, &from);
          /* From here, we will loop all over to the beginning of the
             while(1) block.  */
@@ -621,6 +751,10 @@ manage_mt_worker (void *arg, bool async)
 
              /* Post-processing.  */
 
+             /* Flush the used message buffers.  */
+             flush_string_buffers (bucket, string_buffers,
+                                   string_item_to_flush);
+             
              pthread_mutex_lock (&bucket->lock);
              /* We have to add ourselves to the free list before (or
                 at the same time) as removing the client from the
@@ -684,6 +818,7 @@ manage_mt_worker (void *arg, bool async)
              
              /* Now listen for the next message, with a timeout.  */
              from = manager;
+             l4_accept (acceptor);
              msg_tag = l4_xreceive_timeout (manager, timeout, &from);
 
              /* From here, we will loop to the beginning of the
@@ -692,6 +827,10 @@ manage_mt_worker (void *arg, bool async)
        }
     }
 
+  /* Free all string item buffers */
+  free_string_buffers (bucket, string_buffers,
+                      bucket->string_buf_count); 
+
   /* At this point, we have been canceled while being on the free
      list, so we should go away.  */
 
@@ -742,9 +881,10 @@ manage_mt_worker_async (void *arg)
    becomes free.  If we are interrupted while blocking, return
    l4_nilthread.  */
 static l4_thread_id_t
-manage_mt_get_next_worker (struct worker_info *info, pthread_t *worker_thread)
+manage_mt_get_next_worker (struct generic_worker_info *generic_info,
+                          pthread_t *worker_thread)
 {
-  hurd_cap_bucket_t bucket = info->bucket;
+  hurd_cap_bucket_t bucket = generic_info->bucket;
   l4_thread_id_t worker = l4_nilthread;
   _hurd_cap_list_item_t worker_item;
 
@@ -761,12 +901,28 @@ manage_mt_get_next_worker (struct worker
        err = EAGAIN;
       else
        {
-         err = pthread_create_from_l4_tid_np (worker_thread, NULL,
-                                              worker, manage_mt_worker_sync,
-                                              info);
-         /* Return the thread to the pool.  */
-         if (err)
-           pthread_pool_add_np (worker);
+         struct worker_info *info = malloc (sizeof (struct worker_info));
+         if (!info)
+           err = ENOMEM;
+         else
+           {
+             info->generic_info = generic_info;
+             err = allocate_string_buffers (bucket,
+                                            &info->string_buffers);
+             if (!err)
+               {
+                 err = pthread_create_from_l4_tid_np (worker_thread, NULL,
+                                                      worker, 
manage_mt_worker_sync,
+                                                      info);
+                 /* Return the thread to the pool.  */
+                 if (err)
+                   {
+                     free_string_buffers (bucket, info->string_buffers,
+                                          bucket->string_buf_count);
+                     pthread_pool_add_np (worker);
+                   }
+               }
+           }
        }
 
       if (!err)
@@ -824,10 +980,11 @@ manage_mt_get_next_worker (struct worker
 static void *
 worker_alloc_async (void *arg)
 {
-  struct worker_info *info = (struct worker_info *) arg;
-  hurd_cap_bucket_t bucket = info->bucket;
+  struct generic_worker_info *generic_info;
+  generic_info = (struct generic_worker_info *) arg;
+  hurd_cap_bucket_t bucket = generic_info->bucket;
   error_t err;
-
+  
   pthread_mutex_lock (&bucket->lock);
   if (bucket->state == _HURD_CAP_STATE_BLACK)
     {
@@ -856,15 +1013,30 @@ worker_alloc_async (void *arg)
            err = EAGAIN;
          else
            {
-             err = pthread_create_from_l4_tid_np (&worker_thread, NULL,
-                                                  worker,
-                                                  manage_mt_worker_async,
-                                                  info);
-             /* Return the thread to the pool.  */
-             if (err)
-               pthread_pool_add_np (worker);
+             struct worker_info *info = malloc (sizeof (struct worker_info));
+             if (!info)
+               err = ENOMEM;
+             else
+               {
+                 info->generic_info = generic_info;
+                 err = allocate_string_buffers (bucket,
+                                                &info->string_buffers);
+                 if (!err)
+                   {
+                     err = pthread_create_from_l4_tid_np (&worker_thread, NULL,
+                                                          worker,
+                                                          
manage_mt_worker_async,
+                                                          info);
+                     /* Return the thread to the pool.  */
+                     if (err)
+                       {
+                         free_string_buffers (bucket, info->string_buffers,
+                                              bucket->string_buf_count);
+                         pthread_pool_add_np (worker);
+                       }
+                   }
+               }
            }
-
          if (!err)
            {
              pthread_detach (worker_thread);
@@ -925,15 +1097,18 @@ hurd_cap_bucket_manage_mt (hurd_cap_buck
   l4_time_t global_timeout;
   pthread_t worker_thread;
   l4_thread_id_t worker;
-  struct worker_info info;
+  struct generic_worker_info generic_info;
   _hurd_cap_list_item_t item;
+  void **string_buffers;
+  l4_word_t string_item_to_flush = 0;
+  l4_msg_buffer_t msg_buffer;
 
   global_timeout = (global_timeout_sec == 0) ? L4_NEVER
     : l4_time_period (UINT64_C (1000000) * global_timeout_sec);
 
-  info.bucket = bucket;
-  info.manager_tid = l4_myself ();
-  info.timeout = (worker_timeout_sec == 0) ? L4_NEVER
+  generic_info.bucket = bucket;
+  generic_info.manager_tid = l4_myself ();
+  generic_info.timeout = (worker_timeout_sec == 0) ? L4_NEVER
     : l4_time_period (UINT64_C (1000000) * worker_timeout_sec);
 
   /* We create the first worker thread ourselves, to catch any
@@ -941,10 +1116,19 @@ hurd_cap_bucket_manage_mt (hurd_cap_buck
   worker = pthread_pool_get_np ();
   if (worker == l4_nilthread)
     return EAGAIN;
+  struct worker_info *info = malloc (sizeof (struct worker_info));
+  if (!info)
+    return ENOMEM;
+  info->generic_info = &generic_info;
+  err = allocate_string_buffers (bucket, &info->string_buffers);
+  if (err)
+    return err;
   err = pthread_create_from_l4_tid_np (&worker_thread, NULL,
-                                      worker, manage_mt_worker_sync, &info);
+                                      worker, manage_mt_worker_sync, info);
   if (err)
     {
+      free_string_buffers (bucket, info->string_buffers,
+                          bucket->string_buf_count);
       /* Return the thread to the pool.  */
       pthread_pool_add_np (worker);
       return err;
@@ -959,7 +1143,7 @@ hurd_cap_bucket_manage_mt (hurd_cap_buck
 
       /* Asynchronous worker thread allocation is requested.  */
       err = pthread_create (&bucket->worker_alloc, NULL,
-                           worker_alloc_async, &info);
+                           worker_alloc_async, &generic_info);
       
       if (err)
        {
@@ -974,19 +1158,35 @@ hurd_cap_bucket_manage_mt (hurd_cap_buck
   bucket->is_managed = true;
   bucket->is_manager_waiting = false;
   pthread_mutex_unlock (&bucket->lock);
+
+  err = allocate_string_buffers (bucket, &string_buffers);
+  if (err)
+    return err;
+  get_msg_buffer (bucket, string_buffers, msg_buffer);
   
   while (1)
     {
       l4_thread_id_t from = l4_anythread;
       l4_msg_tag_t msg_tag;
 
-      /* We never accept any map or grant items.  FIXME: For now, we
-        also do not accept any string buffer items.  */
-      l4_accept (L4_UNTYPED_WORDS_ACCEPTOR);
-
+      if (bucket->string_buf_count)
+       {
+         /* We never accept any map or grant items. */
+         /* FIXME: maybe we should just do it once, depending if
+            flushing memory modifies its location */
+         l4_accept_strings (L4_STRING_ITEMS_ACCEPTOR, msg_buffer);
+       }
+      else
+       {
+         l4_accept (L4_UNTYPED_WORDS_ACCEPTOR);
+       }
+      
       /* Because we do not accept any string items, we do not actually
         need to set the Xfer timeouts.  But this is what we want to set
         them to when we eventually do support string items.  */
+      /* FIXME: separate setting the local and remote timeouts if
+        using the more complete pistachio patch*/
+      /* Only works with the simplest pistachio patch for now */
       l4_set_xfer_timeouts (l4_timeouts (L4_ZERO_TIME, L4_ZERO_TIME));
 
       /* FIXME: Make sure we have enabled deferred cancellation, and
@@ -1014,6 +1214,12 @@ hurd_cap_bucket_manage_mt (hurd_cap_buck
              err = ECANCELED;
              break;
            }
+         else if (ipc_err == L4_IPC_MSG_OVERFLOW
+                  || ipc_err == L4_IPC_XFER_TIMEOUT_PARTNER
+                  || ipc_err == L4_IPC_XFER_TIMEOUT_INVOKER)
+           {
+             continue;
+           }
          else
            {
              assert (((err_code >> 1) & 0x7) == L4_IPC_TIMEOUT);
@@ -1032,6 +1238,24 @@ hurd_cap_bucket_manage_mt (hurd_cap_buck
        }
       else
        {
+
+         /* Modify the message so that we send the manager string items. */
+         
+         if (EXPECT_FALSE (l4_typed_words (msg_tag)))
+           {
+             /* Slow path. Modify the message */
+             l4_msg_t msg;
+             l4_msg_store_parsed (msg_tag, msg,
+                                  &string_item_to_flush);
+             msg_tag = l4_msg_msg_tag (msg);
+             l4_msg_load (msg);
+           }
+         else
+           {
+             /* Fast path */
+             string_item_to_flush = 0; 
+           }
+
          /* Propagate the message to the worker thread.  */
          l4_set_propagation (&msg_tag);
          l4_set_virtual_sender (from);
@@ -1045,10 +1269,14 @@ hurd_cap_bucket_manage_mt (hurd_cap_buck
          msg_tag = l4_lcall (worker);
          assert (l4_ipc_succeeded (msg_tag));
 
+         /* Flush every used message buffer.  */
+         flush_string_buffers (bucket, string_buffers,
+                               string_item_to_flush);
+
          if (EXPECT_TRUE (l4_label (msg_tag)
                           == _HURD_CAP_MSG_WORKER_ACCEPTED))
            {
-             worker = manage_mt_get_next_worker (&info, &worker_thread);
+             worker = manage_mt_get_next_worker (&generic_info, 
&worker_thread);
              if (worker == l4_nilthread)
                {
                  /* The manage_mt_get_next_worker thread was
@@ -1070,6 +1298,11 @@ hurd_cap_bucket_manage_mt (hurd_cap_buck
      sequence.  */
   assert (!bucket->pending_rpcs);
 
+  /* Free all string item buffers */
+  free_string_buffers (bucket,
+                      string_buffers,
+                      bucket->string_buf_count);
+
   /* First shutdown the allocator thread, if any.  */
   if (bucket->is_worker_alloc_async)
     {
diff -rup 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/cap-server-intern.h
 hurd-l4/libhurd-cap-server/cap-server-intern.h
--- 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/cap-server-intern.h
  2005-02-14 01:22:16.000000000 +0000
+++ hurd-l4/libhurd-cap-server/cap-server-intern.h      2005-02-23 
17:56:54.000000000 +0000
@@ -447,8 +447,15 @@ struct _hurd_cap_bucket
 
   /* If WORKER_ALLOC_ASYNC is true, this is the allocator thread.  */
   pthread_t worker_alloc;
-};
+  
+  /* Number of string buffers we accept */
+  int string_buf_count;
+
+  /* Array whose size is STRING_BUF_COUNT containing the sizes of each
+     string buffer for receiving string items */
+  size_t *string_buf_sizes;
 
+};
 
 /* Return true if there are still outstanding RPCs in this bucket
    BUCKET, and fails if not.  This is only valid if
diff -rup 
/home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/cap-server.h 
hurd-l4/libhurd-cap-server/cap-server.h
--- /home/racin/src/hurd/mainline/darcs/hurd-l4/libhurd-cap-server/cap-server.h 
2005-02-14 01:22:16.000000000 +0000
+++ hurd-l4/libhurd-cap-server/cap-server.h     2005-02-23 17:56:54.000000000 
+0000
@@ -460,9 +460,13 @@ void hurd_cap_obj_resume (hurd_cap_obj_t
 /* Buckets are a set of capabilities, on which RPCs are managed
    collectively.  */
 
-/* Create a new bucket and return it in R_BUCKET.  */
-error_t hurd_cap_bucket_create (hurd_cap_bucket_t *r_bucket);
-
+/* Create a new bucket and return it in R_BUCKET.
+   STRING_BUF_SIZES is an array of STRING_BUF_COUNT elements
+   specifying the number and size of each receive string
+   buffers. Returns EINVAL if the number of string buffers is invalid.  */
+error_t hurd_cap_bucket_create (hurd_cap_bucket_t *r_bucket,
+                               int string_buf_count,
+                               size_t *string_buf_sizes);
 
 /* Free the bucket BUCKET, which must not be used.  */
 void hurd_cap_bucket_free (hurd_cap_bucket_t bucket);
diff -rup /home/racin/src/hurd/mainline/darcs/hurd-l4/libl4/l4/gnu/ipc.h 
hurd-l4/libl4/l4/gnu/ipc.h
--- /home/racin/src/hurd/mainline/darcs/hurd-l4/libl4/l4/gnu/ipc.h      
2005-02-14 01:22:16.000000000 +0000
+++ hurd-l4/libl4/l4/gnu/ipc.h  2005-02-23 17:56:54.000000000 +0000
@@ -583,6 +583,13 @@ l4_msg_put_string_item (l4_msg_t msg, l4
   _L4_msg_put_string_item (msg, nr, string_item);
 }
 
+static inline void
+_L4_attribute_always_inline
+l4_msg_store_parsed (l4_msg_tag_t tag, l4_msg_t msg,
+                     l4_word_t *string_buffer_used)
+{
+  _L4_msg_store_parsed (tag, msg, string_buffer_used);
+}
 
 static inline l4_word_t
 _L4_attribute_always_inline
diff -rup /home/racin/src/hurd/mainline/darcs/hurd-l4/libl4/l4/ipc.h 
hurd-l4/libl4/l4/ipc.h
--- /home/racin/src/hurd/mainline/darcs/hurd-l4/libl4/l4/ipc.h  2005-02-14 
01:22:16.000000000 +0000
+++ hurd-l4/libl4/l4/ipc.h      2005-02-23 17:56:54.000000000 +0000
@@ -930,6 +930,84 @@ _L4_msg_get (_L4_msg_t msg, _L4_word_t *
     __builtin_memcpy (any_typed++, mrs++, sizeof (_L4_word_t));
 }
 
+/* The following is not part of the L4 official ABI.
+   Get a message from MRs and BRs so that the message buffers poing to
+   receive string items (instead of send string items).
+   Untyped words, map items and grant items are kept "as is".
+   Also returns the number of receive string items in
+   STRING_BUFFER_USED.
+   The BRs have to be all simple string items.
+*/ 
+static inline void
+_L4_attribute_always_inline
+_L4_msg_store_parsed (_L4_msg_tag_t tag, _L4_msg_t msg,
+                     _L4_word_t *string_buffer_used)
+{
+  __L4_msg_tag_t _tag = { .raw = tag };
+  _L4_store_mrs (1, _tag.untyped, &msg[1]); 
+
+  int rcv_buffer_num = 2;
+  int typed_items = 0;
+
+  if (_tag.typed)
+    {
+      _L4_word_t read_num = _tag.untyped + 1;
+      _L4_word_t write_num = read_num;
+      int not_last;
+
+      do
+       {
+         __L4_string_item_t _string_item;
+         _L4_store_mrs (read_num, 2, _string_item.mr);
+         read_num += 2;
+         __L4_string_item_t *string_item = &_string_item;
+
+         not_last = string_item->not_last;
+         typed_items ++;
+         if (string_item->_zero == 0)
+           {
+             /* The item is a string item. */
+             _L4_word_t rcv_address;
+             _L4_word_t rcv_length = 0;
+             _L4_store_br (rcv_buffer_num, &rcv_address);
+             rcv_buffer_num += 2;
+             int cont;
+             do
+               {
+                 cont = string_item->cont;
+                 rcv_length += (string_item->nr_substrings + 1)
+                   * (string_item->length);
+                 read_num += string_item->nr_substrings;
+                 _L4_store_mrs (read_num, 2, _string_item.mr);
+                 string_item = &_string_item;
+               }
+             while (cont);
+             _L4_string_item_t string_item_write;
+             string_item_write = _L4_string_item (rcv_length,
+                                                  (void *) rcv_address);
+             __L4_string_item_t _string_item_write;
+             __builtin_memcpy (&_string_item_write,
+                               &string_item_write,
+                               sizeof (_L4_string_item_t));
+             _string_item_write.not_last = not_last;
+             __builtin_memcpy (&_string_item,
+                               &_string_item_write,
+                               sizeof (__L4_string_item_t));
+           }
+         __builtin_memcpy (&msg[write_num],
+                           &_string_item,
+                           sizeof (_L4_string_item_t));
+         write_num += 2;
+       }
+      while (not_last);
+    }
+  
+  /* Modifies the message tag */
+  _tag.typed = typed_items * 2;
+  _L4_set_msg_msg_tag (msg, _tag.raw);
+
+  *string_buffer_used = ((rcv_buffer_num/2) -1);
+}
 
 static inline _L4_word_t
 _L4_attribute_always_inline
diff -rup /home/racin/src/hurd/mainline/darcs/hurd-l4/physmem/physmem.c 
hurd-l4/physmem/physmem.c
--- /home/racin/src/hurd/mainline/darcs/hurd-l4/physmem/physmem.c       
2005-02-14 01:22:16.000000000 +0000
+++ hurd-l4/physmem/physmem.c   2005-02-23 17:56:54.000000000 +0000
@@ -256,7 +256,7 @@ main (int argc, char *argv[])
   if (err)
     panic ("container_class_init: %i\n", err);
 
-  err = hurd_cap_bucket_create (&bucket);
+  err = hurd_cap_bucket_create (&bucket, 0, NULL);
   if (err)
     panic ("bucket_create: %i\n", err);
 
diff -rup /home/racin/src/hurd/mainline/darcs/hurd-l4/ruth/ruth.c 
hurd-l4/ruth/ruth.c
--- /home/racin/src/hurd/mainline/darcs/hurd-l4/ruth/ruth.c     2005-02-14 
01:22:16.000000000 +0000
+++ hurd-l4/ruth/ruth.c 2005-02-23 17:56:54.000000000 +0000
@@ -174,7 +174,7 @@ main (int argc, char *argv[])
   if (err)
     panic ("ruth_class_init: %i\n", err);
 
-  err = hurd_cap_bucket_create (&bucket);
+  err = hurd_cap_bucket_create (&bucket, 0, NULL);
   if (err)
     panic ("bucket_create: %i\n", err);
 
diff -rup /home/racin/src/hurd/mainline/darcs/hurd-l4/task/task.c 
hurd-l4/task/task.c
--- /home/racin/src/hurd/mainline/darcs/hurd-l4/task/task.c     2005-02-14 
01:22:16.000000000 +0000
+++ hurd-l4/task/task.c 2005-02-23 17:56:54.000000000 +0000
@@ -256,7 +256,7 @@ main (int argc, char *argv[])
   if (err)
     panic ("task_class_init: %i", err);
 
-  err = hurd_cap_bucket_create (&bucket);
+  err = hurd_cap_bucket_create (&bucket, 0, NULL);
   if (err)
     panic ("bucket_create: %i", err);
 

Libc&Deva Changelog:

deva/:
2005-02-08  Matthieu Lemerre  <address@hidden>

        * deva.c (main): Now accepts one string item.

        * device-serial.c (serial_irq_handler): Sets fifo_full, enable TX
        interrupts only once.

        * device.h (struct device): Modified io_read signature.
        (IO_READ_MAX): New constant.
        (struct device): Added fifo_full field for serial.
        * device.h (struct device): Modified io_write signature.
        
        * device-console.c (console_io_write): Now takes a string as an
        argument.
        (console_io_read): Likewise.
        * device-serial.c (serial_io_write): Likewise.
        (serial_io_write): Likewise.

libc/:
2005-02-05  Matthieu Lemerre  <address@hidden>

        * hurd-l4/sysdeps/l4/hurd/read.c (deva_read): New function.
        (__libc_read): Now use deva_read.
        (deva_getchar): Removed this function.

        * hurd-l4/sysdeps/l4/hurd/write.c (deva_write): New function.
        (__libc_read): Now use deva_write.
        (deva_putchar): Removed this function.

libl4/:
2005-02-04  Matthieu Lemerre  <address@hidden>

        * l4/gnu/ipc.h (l4_msg_get_simple_string_item): New function.
        (l4_simple_string_item_size): New function.

        * l4/ipc.h (_L4_msg_get_simple_string_item): New function.
        (_L4_simple_string_item_size): New function.

Patch:

--- hurd-l4/deva/deva.c 2005-02-23 17:56:54.000000000 +0000
+++ hurd-l4/deva/deva.c 2005-02-22 20:41:52.000000000 +0000
@@ -266,7 +266,8 @@ main (int argc, char *argv[])
   if (err)
     panic ("device_class_init: %i\n", err);
 
-  err = hurd_cap_bucket_create (&bucket, 0, NULL);
+  size_t string_item_sizes[1] = {4096};
+  err = hurd_cap_bucket_create (&bucket, 1, string_item_sizes);
   if (err)
     panic ("bucket_create: %i\n", err);
 
diff -rup hurd-l4/deva/device-console.c 
/home/racin/src/hurd/work/string/darcs/string-complete/hurd-l4/deva/device-console.c
--- hurd-l4/deva/device-console.c       2005-02-14 01:22:17.000000000 +0000
+++ hurd-l4/deva/device-console.c       2005-02-16 19:30:57.000000000 +0000
@@ -140,32 +140,53 @@ console_init (device_t *dev)
 }
 
 
-static error_t
-console_io_read (device_t *dev, int *chr)
+static size_t
+console_io_read (device_t *dev, unsigned char *string, size_t count)
 {
-  unsigned char b = '\x00';
+  size_t bytes_copied = 0;
+  int ret = 0;
 
   pthread_mutex_lock (&dev->console.lock);
-  while (!dev->console.input_len)
-    pthread_cond_wait (&dev->console.cond, &dev->console.lock);
-  b = dev->console.input[0];
-  dev->console.input_len--;
-  memmove (&dev->console.input[0], &dev->console.input[1],
-          dev->console.input_len);
+  while (!ret && bytes_copied < count)
+    {
+      while (!dev->console.input_len)
+       {
+         pthread_cond_wait (&dev->console.cond, &dev->console.lock);
+       }
+      size_t size_max = ((count - bytes_copied) < dev->console.input_len
+                        ? (count - bytes_copied) : dev->console.input_len);
+      int i;
+      for (i = 0; i < size_max; i++)
+       {
+         string[bytes_copied++] = dev->console.input[i];
+         dev->console.input_len --;
+         if (dev->console.input[i] == '\n')
+           {
+             ret = 1;
+             break;
+           }
+       }
+
+      if (dev->console.input_len)
+       {
+         memmove (&dev->console.input[0], &dev->console.input[size_max],
+                  dev->console.input_len);
+       }
+    }
   pthread_mutex_unlock (&dev->console.lock);
 
-  *chr = b;
-
-  return 0;
+  return bytes_copied;
 }
 
-
-static error_t
-console_io_write (device_t *dev, int chr)
+static size_t
+console_io_write (device_t *dev, unsigned char *string, size_t count)
 {
-  putchar ((unsigned char) chr);
-
-  return 0;
+  int i;
+  for (i = 0; i < count; i++)
+    {
+      putchar (string[i]);
+    }
+  return count;
 }
 
 
diff -rup hurd-l4/deva/device-serial.c 
/home/racin/src/hurd/work/string/darcs/string-complete/hurd-l4/deva/device-serial.c
--- hurd-l4/deva/device-serial.c        2005-02-14 01:22:17.000000000 +0000
+++ hurd-l4/deva/device-serial.c        2005-02-16 19:30:57.000000000 +0000
@@ -118,6 +118,9 @@ serial_irq_handler (void *_serial)
   if (result)
     panic ("setting serial irq pager failed: %i", result);
  
+  /* Enable interrupts for TX.  */
+  outb (0x3, UART_IER);
+
 #define l4_reply_receive(tid)                                          \
   ({ l4_thread_id_t dummy;                                             \
   l4_ipc (tid, tid, l4_timeouts (L4_ZERO_TIME, L4_NEVER), &dummy); })
@@ -180,31 +183,28 @@ serial_irq_handler (void *_serial)
                /* Update the status.  */
                b = inb (UART_LSR);
              }
-
+           
+           dev->serial.fifo_not_full = (b & (1 << 5));
+           
            if (tx != 0)
              {
-               if (len == SERIAL_MAX && dev->serial.output_wait)
-                 {
-                   /* There is now some more space.  */
-                   pthread_cond_broadcast (&dev->serial.cond);
-                   dev->serial.output_wait = 0;
-                 }
-
-               len -= tx;
-               dev->serial.output_len = len;
-
-               if (len == 0)
-                 /* Disable interrupts for TX.  */
-                 outb (0x1, UART_IER);
-                   
-               else
-                 memmove (&dev->serial.output[0],
-                          &dev->serial.output[tx], len);
+               if (len == SERIAL_MAX && dev->serial.output_wait)
+                 {
+                   /* There is now some more space.  */
+                   pthread_cond_broadcast (&dev->serial.cond);
+                   dev->serial.output_wait = 0;
+                 }
+         
+               len -= tx;
+               dev->serial.output_len = len;
+         
+               memmove (&dev->serial.output[0],
+                        &dev->serial.output[tx], len);
              }
-           }
+         }
          pthread_mutex_unlock (&dev->serial.lock);
        }         
-
+      
       l4_load_mr (0, 0);
       l4_reply_receive (irq);
     }
@@ -243,82 +243,99 @@ serial_init (device_t *dev)
 }
 
 
-static error_t
-serial_io_read (device_t *dev, int *chr)
+static size_t
+serial_io_read (device_t *dev, unsigned char *string, size_t count)
 {
+  size_t bytes_copied = 0;
+  int ret = 0;
+
   pthread_mutex_lock (&dev->serial.lock);
-  while (!dev->serial.input_len)
+  while (!ret && bytes_copied < count)
     {
-      dev->serial.input_wait = 1;
-      pthread_cond_wait (&dev->serial.cond, &dev->serial.lock);
+      while (!dev->serial.input_len)
+       {
+         dev->serial.input_wait = 1;
+         pthread_cond_wait (&dev->serial.cond, &dev->serial.lock);
+       }
+      size_t size_max = ((count - bytes_copied) < dev->serial.input_len
+                        ? (count - bytes_copied) : dev->serial.input_len);
+      int i;
+      for (i = 0; i < size_max; i++)
+       {
+         string[bytes_copied++] = dev->serial.input[i];
+         dev->serial.input_len --;
+         if (dev->serial.input[i] == '\n')
+           {
+             ret = 1;
+             break;
+           }
+       }
+
+      if (dev->serial.input_len)
+       {
+         memmove (&dev->serial.input[0], &dev->serial.input[size_max],
+                  dev->serial.input_len);
+       }
     }
-  *chr = dev->serial.input[0];
-  dev->serial.input_len--;
-  memmove (&dev->serial.input[0], &dev->serial.input[1],
-          dev->serial.input_len);
   pthread_mutex_unlock (&dev->serial.lock);
-
-  return 0;
+  return bytes_copied;
 }
 
 
-static error_t
-serial_io_write (device_t *dev, int chr)
+static size_t
+serial_io_write (device_t *dev, unsigned char* buffer, size_t buffer_len)
 {
-  int old_len;
+  size_t bytes_copied = 0;
 
   pthread_mutex_lock (&dev->serial.lock);
-  while (dev->serial.output_len == SERIAL_MAX)
+  while (bytes_copied < buffer_len)
     {
-      dev->serial.output_wait = 1;
-      pthread_cond_wait (&dev->serial.cond, &dev->serial.lock);
-    }
-
-  old_len = dev->serial.output_len;
-
-  if (old_len == 0)
-    {
-      /* The output queue was empty, this means that the TX interrupts
-        are disabled (the irq handler thread disables them after
-        sending the last character.  We have to refill the buffer and
-        at the same time re-activate the transmit interrupts.  For
-        this, we need to enable the IRQ and write one character to
-        get things rolling.  This makes only sense if we are sending
-        at least two characters.  Another approach would be to cancel
-        the pending IPC operation in the IRQ thread and let it
-        reactivate the IRQ in this case.  */
-
-      /* Right now, only one character is sent always.  No need for
-        IRQs.  */
-#if 0
-      if (buffer_len > 1)
+      while (dev->serial.output_len == SERIAL_MAX)
        {
-         memcpy (&dev->serial.output[dev->serial.output_len],
-                 &buffer[1], buffer_len - 1);
+         dev->serial.output_wait = 1;
+         pthread_cond_wait (&dev->serial.cond, &dev->serial.lock);
+       }
 
-         /* Enable interrupts for TX.  */
-         outb (0x3, UART_IER);
+      int old_len = dev->serial.output_len;
+      size_t output_room = SERIAL_MAX - old_len;
 
+      if (old_len == 0 && dev->serial.fifo_not_full)
+       {
+         /* The output queue is empty, so we have to refill the
+            buffer and trigger a transmit interrupts, so that the
+            interrupt thread can handle the transmission of the
+            message.  For this, we need to write one character to get
+            things rolling.  We can do this since the fifo is not
+            full. If the fifo is full, we already know that
+            interrupts will be triggered.  */
+         size_t bytes_to_copy = ((buffer_len - bytes_copied - 1) < output_room
+                                 ? (buffer_len - bytes_copied - 1) : 
output_room);
+         memcpy (&dev->serial.output[0], 
+                 &buffer[bytes_copied + 1], bytes_to_copy);
+         
+         dev->serial.output_len = bytes_to_copy;
+         
          /* Send first character to make sure the next TX IRQ comes
             soon.  */
-         outb (buffer[0], UART_DR);
+         outb (buffer[bytes_copied], UART_DR);
+         
+         bytes_copied += bytes_to_copy + 1;
        }
       else
-#endif
        {
-         /* Only one character, enabling IRQs makes no sense, as the
-            next IRQ would only come after sending this first
-            character.  */
-         outb (chr, UART_DR);
+         /* Appending the buffer to the serial output buffer */
+         size_t bytes_to_copy = ((buffer_len - bytes_copied) < output_room
+                                 ? (buffer_len - bytes_copied) : output_room);
+         
+         memcpy (&dev->serial.output[dev->serial.output_len],
+                 &buffer[bytes_copied], bytes_to_copy);
+         dev->serial.output_len += bytes_to_copy;
+         bytes_copied += bytes_to_copy;
        }
     }
-  else
-    {
-      dev->serial.output[++dev->serial.output_len] = chr;
-    }
   pthread_mutex_unlock (&dev->serial.lock);
 
-  return 0;
+  return bytes_copied;
 }
 
 
@@ -334,6 +351,7 @@ device_serial_init (device_t *dev)
   dev->serial.input_wait = 0;
   dev->serial.output_len = 0;
   dev->serial.output_wait = 0;
+  dev->serial.fifo_not_full = 0;
 
   /* We know this is only called once, so what the hell.  */
   serial_init (dev);
diff -rup hurd-l4/deva/device.c 
/home/racin/src/hurd/work/string/darcs/string-complete/hurd-l4/deva/device.c
--- hurd-l4/deva/device.c       2005-02-14 01:22:17.000000000 +0000
+++ hurd-l4/deva/device.c       2005-02-16 19:30:57.000000000 +0000
@@ -44,17 +44,24 @@ device_reinit (hurd_cap_class_t cap_clas
 static error_t
 device_io_read (hurd_cap_rpc_context_t ctx)
 {
-  error_t err;
   device_t *dev = hurd_cap_obj_to_user (device_t *, ctx->obj);
-  int chr;
 
-  err =  (*dev->io_read) (dev, &chr);
-  if (err)
-    return err;
+  unsigned char buffer[IO_READ_MAX];
+
+  size_t bytes_read;
+  size_t nbytes = l4_msg_word (ctx->msg, 1);
+  size_t max_len = (nbytes < IO_READ_MAX ? nbytes : IO_READ_MAX);
+
+  bytes_read = (*dev->io_read) (dev, buffer, max_len);
 
   /* Prepare reply message.  */
   l4_msg_clear (ctx->msg);
-  l4_msg_append_word (ctx->msg, (l4_word_t) chr);
+  l4_msg_append_word (ctx->msg, (l4_word_t) bytes_read);
+  if (bytes_read > 0)
+    {
+      l4_string_item_t string_item = l4_string_item (bytes_read, buffer);
+      l4_msg_append_simple_string_item (ctx->msg, string_item);
+    }
 
   return 0;
 }
@@ -64,11 +71,40 @@ static error_t
 device_io_write (hurd_cap_rpc_context_t ctx)
 {
   device_t *dev = hurd_cap_obj_to_user (device_t *, ctx->obj);
-  int chr;
 
-  chr = (int) l4_msg_word (ctx->msg, 1);
+  if ((l4_untyped_words (l4_msg_msg_tag (ctx->msg)) == 2)
+      && (l4_typed_words (l4_msg_msg_tag (ctx->msg)) > 0))
+    {
+      l4_word_t wanted_length = l4_msg_word (ctx->msg, 1);
+      l4_string_item_t string_item;
+      l4_msg_get_simple_string_item (ctx->msg, 0, &string_item);
+      
+      /* Useless test for now, since we do not accept other items */
+      if (l4_is_string_item (&string_item)) 
+       {
+         int string_item_length = l4_simple_string_item_size (&string_item);
+       
+         l4_word_t buffer_address;
+         l4_store_br (2, &buffer_address);
+         
+         unsigned char *string_buffer = (unsigned char *) buffer_address;
+         
+         size_t length = (string_item_length < wanted_length
+                          ? string_item_length : wanted_length);
+
+         size_t bytes_written = (*dev->io_write) (dev, string_buffer, length);
+
+         /* Prepare reply message */
+         l4_msg_clear (ctx->msg);
+         l4_msg_append_word (ctx->msg, (l4_word_t) bytes_written);
+
+         return 0;
+       }
+    }
+  
+  /* Bad message */
+  return (-1);
 
-  return (*dev->io_write) (dev, chr);
 }
 
 
diff -rup hurd-l4/deva/device.h 
/home/racin/src/hurd/work/string/darcs/string-complete/hurd-l4/deva/device.h
--- hurd-l4/deva/device.h       2005-02-14 01:22:17.000000000 +0000
+++ hurd-l4/deva/device.h       2005-02-16 19:30:57.000000000 +0000
@@ -29,11 +29,11 @@ typedef struct device device_t;
 
 struct device
 {
-  /* Read a single character from DEV and return it in CHR.  */
-  error_t (*io_read) (device_t *dev, int *chr);
+  /* Read up to COUNT characters from DEV and put it in BUFFER */
+  size_t (*io_read) (device_t *dev, unsigned char *buffer, size_t count);
 
-  /* Write the single character CHR to DEV.  */
-  error_t (*io_write) (device_t *dev, int chr);
+  /* Write COUNT characters of BUFFER to DEV */
+  size_t (*io_write) (device_t *dev, unsigned char *buffer, size_t count);
 
   /* Private data area.  */
   union
@@ -60,8 +60,10 @@ struct device
       unsigned char output[SERIAL_MAX];
       unsigned int output_len;
       unsigned int output_wait;
+      unsigned int fifo_not_full;
     } serial;
   };
+#define IO_READ_MAX 256
 };
 ;
 
diff -rup hurd-l4/libc/hurd-l4/sysdeps/l4/hurd/read.c 
/home/racin/src/hurd/work/string/darcs/string-complete/hurd-l4/libc/hurd-l4/sysdeps/l4/hurd/read.c
--- hurd-l4/libc/hurd-l4/sysdeps/l4/hurd/read.c 2005-02-14 01:22:16.000000000 
+0000
+++ hurd-l4/libc/hurd-l4/sysdeps/l4/hurd/read.c 2005-02-16 19:32:19.000000000 
+0000
@@ -32,29 +32,35 @@
 #include <hurd/types.h>
 #include <hurd/startup.h>
 
-/* Echo the character CHR on the manager console.  */
-static inline int
+
+
+static inline size_t
 __attribute__((always_inline))
-deva_getchar (void)
+deva_read (char *buffer, size_t nbytes)
 {
-  l4_word_t chr;
+  l4_word_t bytes_read;
   l4_msg_tag_t tag;
   extern struct hurd_startup_data *_hurd_startup_data;
   hurd_cap_handle_t deva_cap_handle
     = _hurd_startup_data->deva_console.cap_handle;
   l4_thread_id_t deva_thread_id = _hurd_startup_data->deva_console.server;
 
-  //  l4_accept (L4_UNTYPED_WORDS_ACCEPTOR);
-
-  tag = l4_niltag;
-  l4_msg_tag_set_label (&tag, 768 /* DEVA_IO_READ */);
-  l4_msg_tag_set_untyped_words (&tag, 1);
-  l4_set_msg_tag (tag);
-  l4_load_mr (1, (l4_word_t) deva_cap_handle);
+  l4_string_item_t string_item = l4_string_item (nbytes, buffer);
+  l4_msg_buffer_t msg_buffer;
+  l4_msg_buffer_clear (msg_buffer);
+  l4_msg_buffer_append_simple_rcv_string (msg_buffer, string_item);
+  l4_accept_strings (L4_STRING_ITEMS_ACCEPTOR, msg_buffer);
+
+  l4_msg_t msg;
+  l4_msg_clear (msg);
+  l4_set_msg_label (msg, 768 /* DEVA_IO_READ */);
+  l4_msg_append_word (msg, deva_cap_handle);
+  l4_msg_append_word (msg, nbytes);
+  l4_msg_load (msg);
   tag = l4_call (deva_thread_id);
 
-  l4_store_mr (1, &chr);
-  return (int) chr;
+  l4_store_mr (1, &bytes_read);
+  return (size_t) bytes_read;
 }
 
 
@@ -85,18 +91,10 @@ __libc_read (int fd, void *buf, size_t n
       return -1;
     }
 
-  res = 0;
-  while (res < nbytes)
-    {
-      int chr = deva_getchar ();
-
-      buffer[res] = (char) chr;
-      res++;
-      if (chr == '\n')
-       break;
-    }
-
+  res = deva_read (buffer, nbytes);
+  
   return res;
+
 }
 libc_hidden_def (__libc_read)
 stub_warning (read)
diff -rup hurd-l4/libc/hurd-l4/sysdeps/l4/hurd/write.c 
/home/racin/src/hurd/work/string/darcs/string-complete/hurd-l4/libc/hurd-l4/sysdeps/l4/hurd/write.c
--- hurd-l4/libc/hurd-l4/sysdeps/l4/hurd/write.c        2005-02-14 
01:22:16.000000000 +0000
+++ hurd-l4/libc/hurd-l4/sysdeps/l4/hurd/write.c        2005-02-16 
19:32:19.000000000 +0000
@@ -33,10 +33,10 @@
 #include <hurd/types.h>
 #include <hurd/startup.h>
 
-/* Echo the character CHR on the manager console.  */
-static inline void
+/* Prints NBYTES of the buffer BUFFER on the manager console. */
+static inline size_t
 __attribute__((always_inline))
-deva_putchar (int chr)
+deva_write (const void* buf, size_t nbytes)
 {
   l4_msg_tag_t tag;
   extern struct hurd_startup_data *_hurd_startup_data;
@@ -45,16 +45,25 @@ deva_putchar (int chr)
   l4_thread_id_t deva_thread_id = _hurd_startup_data->deva_console.server;
 
   //  l4_accept (L4_UNTYPED_WORDS_ACCEPTOR);
-
-  tag = l4_niltag;
-  l4_msg_tag_set_label (&tag, 769 /* DEVA_IO_WRITE */);
-  l4_msg_tag_set_untyped_words (&tag, 2);
-  l4_set_msg_tag (tag);
-  l4_load_mr (1, (l4_word_t) deva_cap_handle);
-  l4_load_mr (2, (l4_word_t) chr);
+  
+  l4_msg_t msg;
+  l4_msg_clear (msg);
+  l4_set_msg_label (msg, 769 /* DEVA_IO_WRITE */);
+  l4_msg_append_word (msg, deva_cap_handle);
+  l4_msg_append_word (msg, nbytes);
+  l4_string_item_t string_item = l4_string_item (nbytes, (char *) buf);
+  l4_msg_append_simple_string_item (msg, string_item);
+  
+  l4_msg_load (msg);
   tag = l4_call (deva_thread_id);
+
+  size_t bytes_written;
+
+  l4_store_mr (1, &bytes_written);
+  return (size_t) bytes_written;
 }
 
+
 
 /* Write NBYTES of BUF to FD.  Return the number written, or -1.  */
 ssize_t
@@ -82,10 +91,8 @@ __libc_write (int fd, const void *buf, s
       return -1;
     }
 
-  res = nbytes;
-  while (nbytes--)
-    deva_putchar (*(((char *)buf)++));
-
+  res = deva_write (buf, nbytes);
+  
   return res;
 }
 libc_hidden_def (__libc_write)
diff -rup hurd-l4/libl4/l4/gnu/ipc.h 
/home/racin/src/hurd/work/string/darcs/string-complete/hurd-l4/libl4/l4/gnu/ipc.h
--- hurd-l4/libl4/l4/gnu/ipc.h  2005-02-23 17:56:54.000000000 +0000
+++ hurd-l4/libl4/l4/gnu/ipc.h  2005-02-20 18:41:30.000000000 +0000
@@ -254,6 +254,14 @@ l4_substring (l4_string_item_t *string_i
 }
 
 
+static inline int
+_L4_attribute_always_inline
+l4_simple_string_item_size (l4_string_item_t *string_item)
+{
+  return _L4_simple_string_item_size (string_item);
+}
+
+
 static inline l4_string_item_t *
 _L4_attribute_always_inline
 l4_add_substring_address_to (l4_string_item_t *string_item, void *source)
@@ -633,6 +641,15 @@ l4_msg_get_string_item (l4_msg_t msg, l4
 }
 
 
+static inline l4_word_t
+_L4_attribute_always_inline
+l4_msg_get_simple_string_item (l4_msg_t msg, l4_word_t nr,
+                              l4_string_item_t *string_item)
+{
+  return _L4_msg_get_simple_string_item (msg, nr, string_item);
+}
+
+
 
 /* IPC interface.  */
 
diff -rup hurd-l4/libl4/l4/ipc.h 
/home/racin/src/hurd/work/string/darcs/string-complete/hurd-l4/libl4/l4/ipc.h
--- hurd-l4/libl4/l4/ipc.h      2005-02-23 17:56:54.000000000 +0000
+++ hurd-l4/libl4/l4/ipc.h      2005-02-20 20:28:34.000000000 +0000
@@ -466,6 +466,18 @@ _L4_string_item_words (void *string_item
 }
 
 
+/* Not part of the L4 official ABI.
+   Gets the size of a simple string item */
+static inline int
+_L4_attribute_always_inline
+_L4_simple_string_item_size (_L4_string_item_t *string_item)
+{
+  __L4_string_item_t _string_item;
+  __builtin_memcpy (&_string_item, string_item, sizeof (_L4_string_item_t));
+  return (int) _string_item.length;
+}
+
+
 /* Append the string described by string item SOURCE to the string
    described by string item STRING_ITEM.  */
 static inline void *
@@ -1280,6 +1292,18 @@ _L4_msg_get_string_item (_L4_msg_t msg, 
   return count;
 }
 
+/* Not in L4 official ABI */
+static inline _L4_word_t
+_L4_attribute_always_inline
+_L4_msg_get_simple_string_item (_L4_msg_t msg, _L4_word_t nr,
+                        _L4_string_item_t *string_item)
+{
+  __L4_msg_tag_t tag = { .raw = _L4_msg_msg_tag (msg)};
+  _L4_word_t pos = 1 + tag.untyped + nr;
+  __builtin_memcpy (string_item, &msg[pos], sizeof (_L4_string_item_t));
+  return sizeof (_L4_string_item_t) / sizeof (_L4_word_t);
+}
+  
 
 /* _L4_ipc convenience interface.  */
 
Thanks,
Matthieu

reply via email to

[Prev in Thread] Current Thread [Next in Thread]