]> Zhao Yanbai Git Server - minix.git/commitdiff
Backport of fix from asynchvfs branch for PM-LOG-VFS-PM deadlock that resulted in...
authorDavid van Moolenbroek <david@minix3.org>
Tue, 24 Jun 2008 13:53:03 +0000 (13:53 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Tue, 24 Jun 2008 13:53:03 +0000 (13:53 +0000)
servers/pm/Makefile
servers/pm/asynsend.c [new file with mode: 0644]
servers/pm/kputc.c [new file with mode: 0644]
servers/pm/main.c
servers/pm/proto.h

index c6343e89a1642f8ce10e9d85155294ea09dff79f..8ae60194f0a563712b5dc825eb63ccc17369a761 100644 (file)
@@ -18,7 +18,7 @@ LDFLAGS = -i
 
 OBJ =  main.o forkexit.o break.o exec.o time.o timers.o \
        signal.o alloc.o utility.o table.o trace.o getset.o misc.o \
-       profile.o
+       profile.o asynsend.o kputc.o
 
 # build local binary
 all build:     $(SERVER)
diff --git a/servers/pm/asynsend.c b/servers/pm/asynsend.c
new file mode 100644 (file)
index 0000000..de7e5d1
--- /dev/null
@@ -0,0 +1,90 @@
+
+#include "pm.h"
+
+#define ASYN_NR        100
+PRIVATE asynmsg_t msgtable[ASYN_NR];
+PRIVATE int first_slot= 0, next_slot= 0;
+
+PUBLIC int asynsend(dst, mp)
+endpoint_t dst;
+message *mp;
+{
+       int r, src_ind, dst_ind;
+       unsigned flags;
+
+       /* Update first_slot */
+       for (; first_slot < next_slot; first_slot++)
+       {
+               flags= msgtable[first_slot].flags;
+               if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE))
+               {
+                       if (msgtable[first_slot].result != OK)
+                       {
+                               printf(
+                       "asynsend: found completed entry %d with error %d\n",
+                                       first_slot,
+                                       msgtable[first_slot].result);
+                       }
+                       continue;
+               }
+               if (flags != AMF_EMPTY)
+                       break;
+       }
+
+       if (first_slot >= next_slot)
+       {
+               /* Reset first_slot and next_slot */
+               next_slot= first_slot= 0;
+       }
+
+       if (next_slot >= ASYN_NR)
+       {
+               /* Tell the kernel to stop processing */
+               r= senda(NULL, 0);
+               if (r != OK)
+                       panic(__FILE__, "asynsend: senda failed", r);
+
+               dst_ind= 0;
+               for (src_ind= first_slot; src_ind<next_slot; src_ind++)
+               {
+                       flags= msgtable[src_ind].flags;
+                       if ((flags & (AMF_VALID|AMF_DONE)) ==
+                               (AMF_VALID|AMF_DONE))
+                       {
+                               if (msgtable[src_ind].result != OK)
+                               {
+                                       printf(
+                       "asynsend: found completed entry %d with error %d\n",
+                                               src_ind,
+                                               msgtable[src_ind].result);
+                               }
+                               continue;
+                       }
+                       if (flags == AMF_EMPTY)
+                               continue;
+#if 0
+                       printf("asynsend: copying entry %d to %d\n",
+                               src_ind, dst_ind);
+#endif
+                       if (src_ind != dst_ind)
+                               msgtable[dst_ind]= msgtable[src_ind];
+                       dst_ind++;
+               }
+               first_slot= 0;
+               next_slot= dst_ind;
+               if (next_slot >= ASYN_NR)
+                       panic(__FILE__, "asynsend: msgtable full", NO_NUM);
+       }
+
+       msgtable[next_slot].dst= dst;
+       msgtable[next_slot].msg= *mp;
+       msgtable[next_slot].flags= AMF_VALID;   /* Has to be last. The kernel 
+                                                * scans this table while we
+                                                * are sleeping.
+                                                */
+       next_slot++;
+
+       /* Tell the kernel to rescan the table */
+       return senda(msgtable+first_slot, next_slot-first_slot);
+}
+
diff --git a/servers/pm/kputc.c b/servers/pm/kputc.c
new file mode 100644 (file)
index 0000000..b0c53b0
--- /dev/null
@@ -0,0 +1,149 @@
+/* A server must occasionally print some message.  It uses a simple version of 
+ * printf() found in the system lib that calls kputc() to output characters.
+ * Printing is done with a call to the kernel, and not by going through FS.
+ *
+ * This routine can only be used by servers and device drivers.  The kernel
+ * must define its own kputc(). Note that the log driver also defines its own 
+ * kputc() to directly call the TTY instead of going through this library.
+ */
+
+#include "pm.h"
+#include <string.h>
+#include <minix/com.h>
+
+#define OVERFLOW_STR "[...]\n"
+
+#define PRINTPROCS (sizeof(procs)/sizeof(procs[0]))
+
+static char print_buf[80];     /* output is buffered here */
+
+int kputc_use_private_grants= 0;
+
+static int buf_count = 0;      /* # characters in the buffer */
+static int buf_offset = 0;     /* Start of current line in buffer */
+static int procs[] = OUTPUT_PROCS_ARRAY;
+static cp_grant_id_t printgrants[PRINTPROCS];
+static int procbusy[PRINTPROCS];
+static int do_flush = FALSE;
+static int overflow = FALSE;
+
+/*===========================================================================*
+ *                             kputc                                        *
+ *===========================================================================*/
+void kputc(c)
+int c;
+{
+/* Accumulate another character.  If 0 or buffer full, print it. */
+  int p;
+  message m;
+
+  static int firstprint = 1;
+
+  if (c == 0)
+  {
+       if (buf_count > buf_offset)
+               do_flush= TRUE;
+  }
+  else if (buf_count >= sizeof(print_buf))
+  {
+       overflow= TRUE;
+       if (buf_count > buf_offset)
+               do_flush= TRUE;
+  }
+  else
+       print_buf[buf_count++] = c;
+
+  if (!do_flush || buf_offset != 0)
+       return;
+
+       buf_offset= buf_count;
+       if (kputc_use_private_grants)
+       {
+               for (p= 0; p<PRINTPROCS; p++)
+                       printgrants[p]= GRANT_INVALID;
+               firstprint= 0;
+       }
+       if(firstprint) {
+               for(p = 0; procs[p] != NONE; p++) {
+                       printgrants[p] = GRANT_INVALID;
+               }
+
+               firstprint = 0;
+
+               /* First time? Initialize grant table;
+                * Grant printing processes read copy access to our
+                * print buffer forever. (So buffer can't be on stack!)
+                */
+               for(p = 0; procs[p] != NONE; p++) {
+                       printgrants[p] = cpf_grant_direct(procs[p],
+                               (vir_bytes) print_buf,
+                               sizeof(print_buf), CPF_READ);
+               }
+       }
+
+       do_flush= FALSE;
+       for(p = 0; procs[p] != NONE; p++) {
+               /* Send the buffer to this output driver. */
+               m.DIAG_BUF_COUNT = buf_count;
+               if(GRANT_VALID(printgrants[p])) {
+                       m.m_type = DIAGNOSTICS_S;
+                       m.DIAG_PRINT_BUF_G = (char *) printgrants[p];
+               } else {
+                       m.m_type = DIAGNOSTICS;
+                       m.DIAG_PRINT_BUF_G = print_buf;
+               }
+               if (procs[p] == LOG_PROC_NR)
+               {
+                       procbusy[p]= TRUE;
+                       (void) asynsend(procs[p], &m);
+               }
+               else
+               {
+                       sendrec(procs[p], &m);
+               }
+       }
+}
+
+PUBLIC void diag_repl()
+{
+       endpoint_t driver_e;
+       int p;
+
+       driver_e= m_in.m_source;
+
+       /* Find busy flag to clear */
+       for(p = 0; procs[p] != NONE; p++)
+       {
+               if (procs[p] == driver_e)
+                       break;
+       }
+       if (procs[p] == NONE)
+       {
+               /* Message from wrong source */
+               return;
+       }
+       procbusy[p]= FALSE;
+
+       /* Wait for more replies? */
+       for(p = 0; procs[p] != NONE; p++)
+       {
+               if (procbusy[p])
+                       return;
+       }
+       if (buf_count > buf_offset)
+       {
+               memmove(&print_buf[0], &print_buf[buf_offset], 
+                       buf_count-buf_offset);
+       }
+       buf_count -= buf_offset;
+       buf_offset= 0;
+       if (overflow)
+       {
+               if (buf_count + sizeof(OVERFLOW_STR) > sizeof(print_buf))
+                       buf_count= sizeof(print_buf)-sizeof(OVERFLOW_STR);
+               overflow= FALSE;
+               do_flush= FALSE;
+               printf("%s", OVERFLOW_STR);
+       }
+       kputc(0);
+}
index 1f6123d69db6fffeda3b61699fe682201848d063..4a60bd1e757bbd92757d7247c772da9c99e6e41a 100644 (file)
@@ -124,6 +124,10 @@ PUBLIC int main()
        case GETPUID:
                result= do_getpuid();
                break;
+       case DIAG_REPL :
+               diag_repl();
+               result= SUSPEND;
+               break;
        default:
                /* Else, if the system call number is valid, perform the
                 * call.
index 392f8f6e3956ed842e90e499d2dbdcb37655a320..ac8919efb695e658fff9f03188d57cb1b1557d69 100644 (file)
@@ -27,6 +27,9 @@ _PROTOTYPE( void swap_inqueue, (struct mproc *rmp)                    );
 #endif /* !SWAP */
 _PROTOTYPE(int mem_holes_copy, (struct hole *, size_t *, u32_t *)      );
 
+/* asynsend.c */
+_PROTOTYPE( int asynsend, (endpoint_t dst, message *mp)                        );
+
 /* break.c */
 _PROTOTYPE( int adjust, (struct mproc *rmp,
                        vir_clicks data_clicks, vir_bytes sp)           );
@@ -63,6 +66,9 @@ _PROTOTYPE( void real_cleanup, (struct mproc *rmp)                    );
 /* getset.c */
 _PROTOTYPE( int do_getset, (void)                                      );
 
+/* kputc.c */
+_PROTOTYPE( void diag_repl, (void)                                     );
+
 /* main.c */
 _PROTOTYPE( int main, (void)                                           );