]> Zhao Yanbai Git Server - minix.git/commitdiff
. DS understands publishing and subscribing where keys are in string
authorBen Gras <ben@minix3.org>
Thu, 13 Jul 2006 14:50:23 +0000 (14:50 +0000)
committerBen Gras <ben@minix3.org>
Thu, 13 Jul 2006 14:50:23 +0000 (14:50 +0000)
   form. Subscriptions are regular expressions.
 . different types are stored per key; currently u32 and/or string.
   the same key can be referenced (publish, subscribe, check) as any type.
 . notify()s are sent when subscriptions are triggered (publishing or
   updating of matching keys); optionally, a subscribe flag sends
   updates for all matching keys at subscription time, instead of only
   after updates after subscribing
 . all interfacing to ds is in /usr/src/lib/syslib/ds.c.
 . subscribe is ds_subscribe
   publish functions are ds_publish_<type>
   retrieve functions are ds_retrieve_<type> (one-time retrieval of a value)
   check functions are ds_check_<type> (check for updated key caller
      subscribes to not yet checked for, or ESRCH for none)
 . ramdisk driver updated with new ds interface

drivers/memory/memory.c
include/minix/com.h
lib/syslib/Makefile.in
lib/syslib/ds.c [new file with mode: 0644]
lib/syslib/safecopies.c
servers/ds/main.c
servers/ds/proto.h
servers/ds/store.c
servers/ds/store.h
servers/is/dmp.c
servers/is/dmp_ds.c

index 35b566e95b571e6bd5bce7f0210e3241f1d03fb3..906699e8a73a1ff34c4cb4cb993d3b6b8e77f967 100644 (file)
 #include "../drivers.h"
 #include "../libdriver/driver.h"
 #include <sys/ioc_memory.h>
+#include <minix/ds.h>
 #include "../../kernel/const.h"
 #include "../../kernel/config.h"
 #include "../../kernel/type.h"
 
+#define MY_DS_NAME_BASE "dev:memory:ramdisk_base"
+#define MY_DS_NAME_SIZE "dev:memory:ramdisk_size"
+
 #include <sys/vm.h>
 
 #include "assert.h"
@@ -291,8 +295,8 @@ message *m_ptr;
 PRIVATE void m_init()
 {
   /* Initialize this task. All minor devices are initialized one by one. */
-  phys_bytes ramdev_size;
-  phys_bytes ramdev_base;
+  u32_t ramdev_size;
+  u32_t ramdev_base;
   message m;
   int i, s;
 
@@ -319,10 +323,8 @@ PRIVATE void m_init()
   }
 
   /* See if there are already RAM disk details at the Data Store server. */
-  m.DS_KEY = MEMORY_MAJOR;
-  if (OK == (s = _taskcall(DS_PROC_NR, DS_RETRIEVE, &m))) {
-       ramdev_size = m.DS_VAL_L1;
-       ramdev_base = m.DS_VAL_L2;
+  if(ds_retrieve_u32(MY_DS_NAME_BASE, &ramdev_base) == OK &&
+     ds_retrieve_u32(MY_DS_NAME_SIZE, &ramdev_size) == OK) {
        printf("MEM retrieved size %u and base %u from DS, status %d\n",
                ramdev_size, ramdev_base, s);
        if (OK != (s=sys_segctl(&m_seg[RAM_DEV], (u16_t *) &s, 
@@ -423,15 +425,14 @@ int safe;
        /* Store the values we got in the data store so we can retrieve
         * them later on, in the unfortunate event of a crash.
         */
-       m.DS_KEY = MEMORY_MAJOR;
-       m.DS_VAL_L1 = ramdev_size;
-       m.DS_VAL_L2 = ramdev_base;
-       if (OK != (s = _taskcall(DS_PROC_NR, DS_PUBLISH, &m))) {
+       if(ds_publish_u32(MY_DS_NAME_BASE, ramdev_base) != OK ||
+          ds_publish_u32(MY_DS_NAME_SIZE, ramdev_size) != OK) {
                panic("MEM","Couldn't store RAM disk details at DS.",s);
        }
+
 #if DEBUG
-       printf("MEM stored size %u and base %u at DS, status %d\n",
-           ramdev_size, ramdev_base, s);
+       printf("MEM stored size %u and base %u at DS, names %s and %s\n",
+           ramdev_size, ramdev_base, MY_DS_NAME_BASE, MY_DS_NAME_SIZE);
 #endif
 
        if (OK != (s=sys_segctl(&m_seg[RAM_DEV], (u16_t *) &s, 
index 687598da0746eb2e5aa6b6feb96dbe2ae770b461..cbc5951824884e7304537726812d40ea1d4d53f1 100755 (executable)
@@ -65,6 +65,7 @@
 #  define NEW_KSIG     NOTIFY_FROM(HARDWARE)   /* new kernel signal */
 #  define FKEY_PRESSED NOTIFY_FROM(TTY_PROC_NR)/* function key press */
 #  define DEV_PING     NOTIFY_FROM(RS_PROC_NR) /* driver liveness ping */
+#  define DS_UPDATE    NOTIFY_FROM(DS_PROC_NR) /* subscription update */
 
 /* Shorthands for message parameters passed with notifications. */
 #define NOTIFY_SOURCE          m_source
 #define DS_RQ_BASE             0x800
 
 #define DS_PUBLISH     (DS_RQ_BASE + 0)        /* publish information */
-#define DS_RETRIEVE    (DS_RQ_BASE + 1)        /* retrieve information */
-#define DS_SUBSCRIBE   (DS_RQ_BASE + 2)        /* subscribe to information */
+#define DS_SUBSCRIBE   (DS_RQ_BASE + 1)        /* subscribe to information */
+#define DS_RETRIEVE    (DS_RQ_BASE + 2)        /* retrieve information by name */
+#define DS_CHECK       (DS_RQ_BASE + 3)        /* retrieve updated information */
 
-#  define DS_KEY               m2_i1           /* key for the information */
+/* DS field names: DS_SUBSCRIBE, DS_PUBLISH, DS_RETRIEVE */
+#  define DS_KEY_GRANT         m2_p1           /* key for the information */
+#  define DS_KEY_LEN           m2_i1           /* length of key incl. '\0' */
 #  define DS_FLAGS             m2_i2           /* flags provided by caller */
-#  define DS_AUTH              m2_p1           /* authorization of caller */
-#  define DS_VAL_L1            m2_l1           /* first long data value */
-#  define DS_VAL_L2            m2_l2           /* second long data value */
+
+/* DS_PUBLISH, DS_RETRIEVE */
+#  define DS_VAL               m2_l1           /* data (u32, char *, etc.) */
+#  define DS_VAL_LEN           m2_l2           /* data length */
 
 /*===========================================================================*
  *                Miscellaneous messages used by TTY                        *
index da50d08dc37b6e4a5378e65bf47c2b9c2c01919b..63c0b14e3214cd20f68e2112232cf9937d32b389 100644 (file)
@@ -63,6 +63,7 @@ libsys_FILES=" \
        sys_voutb.c \
        sys_voutl.c \
        sys_voutw.c \
-       taskcall.c"
+       taskcall.c \
+       ds.c"
 
 TYPE=both
diff --git a/lib/syslib/ds.c b/lib/syslib/ds.c
new file mode 100644 (file)
index 0000000..d2b3696
--- /dev/null
@@ -0,0 +1,259 @@
+
+#include <minix/ds.h>
+#include <string.h>
+
+#include "syslib.h"
+
+int
+ds_subscribe(ds_name_regexp, type, flags)
+char *ds_name_regexp;
+int type;
+int flags;
+{
+       int r;
+       message m;
+       cp_grant_id_t g;
+       size_t len;
+
+       len = strlen(ds_name_regexp)+1;
+       g = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) ds_name_regexp, len, CPF_READ);
+
+       if(!GRANT_VALID(g)) 
+               return -1;
+
+       flags &= DS_INITIAL;
+
+       m.DS_KEY_GRANT = (char *) g;
+       m.DS_KEY_LEN = len;
+       m.DS_FLAGS = flags | (type & DS_TYPE_MASK);
+
+       r = _taskcall(DS_PROC_NR, DS_SUBSCRIBE, &m);
+
+       cpf_revoke(g);
+
+       return r;
+}
+
+int ds_publish_u32(ds_name, value)
+char *ds_name;
+u32_t value;
+{
+       int r;
+       message m;
+       cp_grant_id_t g;
+       size_t len;
+
+       len = strlen(ds_name)+1;
+       g = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) ds_name, len, CPF_READ);
+
+       if(!GRANT_VALID(g)) 
+               return -1;
+
+       m.DS_KEY_GRANT = (char *) g;
+       m.DS_KEY_LEN = len;
+       m.DS_FLAGS = DS_TYPE_U32;
+       m.DS_VAL = value;
+       m.DS_VAL_LEN = sizeof(value);
+
+       r = _taskcall(DS_PROC_NR, DS_PUBLISH, &m);
+
+       cpf_revoke(g);
+
+       return r;
+}
+
+int ds_publish_str(ds_name, value)
+char *ds_name;
+char *value;
+{
+       int r;
+       message m;
+       cp_grant_id_t g_key, g_str;
+       size_t len_key, len_str;
+
+       /* Grant for key. */
+       len_key = strlen(ds_name)+1;
+       g_key = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) ds_name, len_key, CPF_READ);
+       if(!GRANT_VALID(g_key)) 
+               return -1;
+
+       /* Grant for value. */
+       len_str = strlen(value)+1;
+       g_str = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) value, len_str, CPF_READ);
+
+       if(!GRANT_VALID(g_str))  {
+               cpf_revoke(g_key);
+               return -1;
+       }
+
+       m.DS_KEY_GRANT = (char *) g_key;
+       m.DS_KEY_LEN = len_key;
+       m.DS_FLAGS = DS_TYPE_STR;
+       m.DS_VAL = g_str;
+       m.DS_VAL_LEN = len_str;
+
+       r = _taskcall(DS_PROC_NR, DS_PUBLISH, &m);
+
+       cpf_revoke(g_key);
+       cpf_revoke(g_str);
+
+       return r;
+}
+
+int ds_retrieve_u32(ds_name, value)
+char *ds_name;
+u32_t *value;
+{
+       int r;
+       message m;
+       cp_grant_id_t g_key;
+       size_t len_key;
+
+       /* Grant for key. */
+       len_key = strlen(ds_name)+1;
+       g_key = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) ds_name, len_key, CPF_READ);
+       if(!GRANT_VALID(g_key)) 
+               return -1;
+
+       /* Do request. */
+       m.DS_KEY_GRANT = (char *) g_key;
+       m.DS_KEY_LEN = len_key;
+       m.DS_FLAGS = DS_TYPE_U32;
+
+       r = _taskcall(DS_PROC_NR, DS_RETRIEVE, &m);
+
+       cpf_revoke(g_key);
+
+       /* Assign u32 value. */
+       *value = m.DS_VAL;
+
+       return r;
+}
+
+int ds_retrieve_str(ds_name, value, len_str)
+char *ds_name;
+char *value;
+size_t len_str;
+{
+       int r;
+       message m;
+       cp_grant_id_t g_key, g_str;
+       size_t len_key;
+
+       /* Grant for key. */
+       len_key = strlen(ds_name)+1;
+       g_key = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) ds_name, len_key, CPF_READ);
+       if(!GRANT_VALID(g_key)) 
+               return -1;
+
+       /* Grant for value. */
+       g_str = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) value, len_str, CPF_WRITE);
+
+       if(!GRANT_VALID(g_str))  {
+               cpf_revoke(g_key);
+               return -1;
+       }
+
+       /* Do request. */
+
+       m.DS_KEY_GRANT = (char *) g_key;
+       m.DS_KEY_LEN = len_key;
+       m.DS_FLAGS = DS_TYPE_STR;
+       m.DS_VAL = g_str;
+       m.DS_VAL_LEN = len_str;
+
+       r = _taskcall(DS_PROC_NR, DS_RETRIEVE, &m);
+
+       cpf_revoke(g_key);
+       cpf_revoke(g_str);
+
+       return r;
+}
+
+int ds_check_str(ds_key, len_key, value, len_str)
+char *ds_key;
+size_t len_key;
+char *value;
+size_t len_str;
+{
+       int r;
+       message m;
+       cp_grant_id_t g_key, g_str;
+
+       if(len_key < 1 || len_str < 1) return -1;
+
+       /* Grant for key. */
+       g_key = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) ds_key, len_key, CPF_WRITE);
+       if(!GRANT_VALID(g_key)) 
+               return -1;
+
+       /* Grant for value. */
+       g_str = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) value, len_str, CPF_WRITE);
+
+       if(!GRANT_VALID(g_str))  {
+               cpf_revoke(g_key);
+               return -1;
+       }
+
+       /* Do request. */
+
+       m.DS_KEY_GRANT = (char *) g_key;
+       m.DS_KEY_LEN = len_key;
+       m.DS_FLAGS = DS_TYPE_STR;
+       m.DS_VAL = g_str;
+       m.DS_VAL_LEN = len_str;
+
+       r = _taskcall(DS_PROC_NR, DS_CHECK, &m);
+
+       cpf_revoke(g_key);
+       cpf_revoke(g_str);
+
+       ds_key[len_key-1] = '\0';
+       value[len_str-1] = '\0';
+
+       return r;
+}
+
+int ds_check_u32(ds_key, len_key, value)
+char *ds_key;
+size_t len_key;
+u32_t *value;
+{
+       int r;
+       message m;
+       cp_grant_id_t g_key;
+
+       if(len_key < 1) return -1;
+
+       /* Grant for key. */
+       g_key = cpf_grant_direct(DS_PROC_NR,
+               (vir_bytes) ds_key, len_key, CPF_WRITE);
+       if(!GRANT_VALID(g_key)) 
+               return -1;
+
+       /* Do request. */
+       m.DS_KEY_GRANT = (char *) g_key;
+       m.DS_KEY_LEN = len_key;
+       m.DS_FLAGS = DS_TYPE_U32;
+
+       r = _taskcall(DS_PROC_NR, DS_CHECK, &m);
+
+       cpf_revoke(g_key);
+
+       ds_key[len_key-1] = '\0';
+
+       /* Assign u32 value. */
+       *value = m.DS_VAL;
+
+       return r;
+}
+
index 0559f976f0027f4d907c719b3de84f9ff9cb170d..468c98d77aa8bfe98bfb873a0c6d28747c1f7935 100644 (file)
@@ -310,3 +310,4 @@ cp_grant_id_t gid;
        return 0;
 }
 
+
index d90c994cf239d0dec21c6ab7e8bd9c98e385bccb..ee76f0c31e1a47ed0243eab25c71362fc742a21f 100644 (file)
@@ -59,6 +59,9 @@ PUBLIC int main(int argc, char **argv)
       case DS_SUBSCRIBE:
          result = do_subscribe(&m);
          break;
+      case DS_CHECK:
+         result = do_check(&m);
+         break;
       case GETSYSINFO:
          result = do_getsysinfo(&m);
          break;
@@ -91,6 +94,9 @@ PRIVATE void init_server(int argc, char **argv)
   sigact.sa_flags = 0;                 /* default behaviour */
   if (sigaction(SIGTERM, &sigact, NULL) < 0) 
       report("DS","warning, sigaction() failed", errno);
+
+  /* Initialize DS. */
+  ds_init();
 }
 
 /*===========================================================================*
index cb0a86a9447f2840bf0c84763416520862222950..e5d1435de9cbbdb7369dba22fb2cf91b266b4411 100644 (file)
@@ -7,4 +7,6 @@ _PROTOTYPE(int main, (int argc, char **argv));
 _PROTOTYPE(int do_publish, (message *m_ptr));
 _PROTOTYPE(int do_retrieve, (message *m_ptr));
 _PROTOTYPE(int do_subscribe, (message *m_ptr));
+_PROTOTYPE(int do_check, (message *m_ptr));
 _PROTOTYPE(int do_getsysinfo, (message *m_ptr));
+_PROTOTYPE(void ds_init, (void));
index c557145d4bd6de53c528ab4db3c022dc5df7c42a..86018ee264e9f766f58b2227e8f55188d555d86d 100644 (file)
@@ -4,40 +4,66 @@
 
 /* Allocate space for the data store. */
 PRIVATE struct data_store ds_store[NR_DS_KEYS];
+PRIVATE struct subscription ds_subs[NR_DS_SUBS];
 PRIVATE int nr_in_use;
 
-PRIVATE _PROTOTYPE(int find_key, (int key, struct data_store **dsp));
-PRIVATE _PROTOTYPE(int set_owner, (struct data_store *dsp, void *auth_ptr));
-PRIVATE _PROTOTYPE(int is_authorized, (struct data_store *dsp, void *auth_ptr));
+PRIVATE _PROTOTYPE(int find_key, (char *key, struct data_store **dsp, int t));
+PRIVATE _PROTOTYPE(int set_owner, (struct data_store *dsp, int auth));
+PRIVATE _PROTOTYPE(int is_authorized, (struct data_store *dsp, int auth));
+PRIVATE _PROTOTYPE(void check_subscribers, (struct data_store *dsp));
 
 
-PRIVATE int set_owner(dsp, ap)
+/*===========================================================================*
+ *                             ds_init                                      *
+ *===========================================================================*/
+PUBLIC void ds_init(void)
+{
+       int i;
+
+       /* Reset data store: data and subscriptions. */
+
+       for(i = 0; i < NR_DS_KEYS; i++) {
+               int b;
+               ds_store[i].ds_flags = 0;
+               for(b = 0; b < BITMAP_CHUNKS(NR_DS_SUBS); b++) {
+                       ds_store[i].ds_old_subs[b] = 0;
+               }
+       }
+       for(i = 0; i < NR_DS_SUBS; i++)
+               ds_subs[i].sub_flags = 0;
+
+       return;
+}
+
+PRIVATE int set_owner(dsp, auth)
 struct data_store *dsp;                                /* data store structure */
-void *ap;                                      /* authorization pointer */
+int auth;
 {
-  /* Authorize the caller. */
   return(TRUE);
 }
 
 
 PRIVATE int is_authorized(dsp, ap)
 struct data_store *dsp;                                /* data store structure */
-void *ap;                                      /* authorization pointer */
+int ap;                                                /* authorization value */
 {
   /* Authorize the caller. */
   return(TRUE);
 }
 
 
-PRIVATE int find_key(key, dsp)
-int key;                                       /* key to look up */
+PRIVATE int find_key(key_name, dsp, type)
+char *key_name;                                        /* key to look up */
 struct data_store **dsp;                       /* store pointer here */
+int type;                                      /* type info */
 {
   register int i;
 
   *dsp = NULL;
   for (i=0; i<NR_DS_KEYS; i++) {
-      if ((ds_store[i].ds_flags & DS_IN_USE) && ds_store[i].ds_key == key) {
+      if ((ds_store[i].ds_flags & DS_IN_USE)           /* valid slot? */
+      &&  ((ds_store[i].ds_flags & type) == type)      /* right type? */
+      && !strcmp(ds_store[i].ds_key, key_name)) {      /* matching name? */
          *dsp = &ds_store[i];
           return(TRUE);                                /* report success */
       }
@@ -50,27 +76,45 @@ PUBLIC int do_publish(m_ptr)
 message *m_ptr;                                        /* request message */
 {
   struct data_store *dsp;
+  char key_name[DS_MAX_KEYLEN];
+  int r, type;
 
   /* Store (key,value)-pair. First see if key already exists. If so, 
    * check if the caller is allowed to overwrite the value. Otherwise
    * find a new slot and store the new value. 
    */
-  if (find_key(m_ptr->DS_KEY, &dsp)) {                 /* look up key */
-      if (! is_authorized(dsp,m_ptr->DS_AUTH)) {       /* check if owner */
-          return(EPERM);
-      }
-  } 
-  else {                                               /* find a new slot */
+  if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 2) {
+       printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
+               m_ptr->m_source);
+       return EINVAL;
+  }
+
+  /* Check type info. */
+  type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
+  if(type != DS_TYPE_U32 && type != DS_TYPE_STR) {
+       printf("DS: bogus type code %lx from %d\n", type, m_ptr->m_source);
+       return EINVAL;
+  }
+
+  /* Copy name from caller. */
+  if ((r=sys_safecopyfrom(m_ptr->m_source,
+       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0, 
+       (vir_bytes) key_name, m_ptr->DS_KEY_LEN, D)) != OK) {
+       printf("DS: publish: copy failed from %d: %d\n", m_ptr->m_source, r);
+       return r;
+  }
+
+  /* Make sure name is 0-terminated. */
+  key_name[DS_MAX_KEYLEN-1] = '\0';
+
+  /* See if it already exists. */
+  if (!find_key(key_name, &dsp, type)) {               /* look up key */
       if (nr_in_use >= NR_DS_KEYS) {
          return(EAGAIN);                               /* store is full */
       } else {
           dsp = &ds_store[nr_in_use];                  /* new slot found */
-         dsp->ds_key = m_ptr->DS_KEY;
-         if (! set_owner(dsp,m_ptr->DS_AUTH)) {        /* associate owner */
-             return(EINVAL);
-         }
-         dsp->ds_nr_subs = 0;                          /* nr of subscribers */
-         dsp->ds_flags = DS_IN_USE;                    /* initialize slot */
+         strcpy(dsp->ds_key, key_name);
+         dsp->ds_flags = DS_IN_USE | m_ptr->DS_FLAGS;  /* initialize slot */
          nr_in_use ++;
       }
   }
@@ -78,59 +122,245 @@ message *m_ptr;                                   /* request message */
   /* At this point we have a data store pointer and know the caller is 
    * authorize to write to it. Set all fields as requested.
    */
-  dsp->ds_val_l1 = m_ptr->DS_VAL_L1;           /* store all data */
-  dsp->ds_val_l2 = m_ptr->DS_VAL_L2;   
-
-  /* If the data is public. Check if there are any subscribers to this key. 
-   * If so, notify all subscribers so that they can retrieve the data, if 
-   * they're still interested.
-   */
-  if ((dsp->ds_flags & DS_PUBLIC) && dsp->ds_nr_subs > 0) {
+  switch(type) {
+       case DS_TYPE_U32:
+         dsp->ds_val.ds_val_u32 = (u32_t) m_ptr->DS_VAL;       /* store data */
+         break;
+       case DS_TYPE_STR:
+         /* store string data: check size, then do copy */
+         if(m_ptr->DS_VAL_LEN < 1 || m_ptr->DS_VAL_LEN > DS_MAX_VALLEN) {
+           printf("DS: publish: bogus len from %d: %d\n",
+             m_ptr->m_source, m_ptr->DS_VAL_LEN);
+           return EINVAL;
+         }
 
-      /* Subscriptions are not yet implemented. */
+         if((r=sys_safecopyfrom(m_ptr->m_source, m_ptr->DS_VAL, 0,
+                 (vir_bytes) dsp->ds_val.ds_val_str,
+                 m_ptr->DS_VAL_LEN, D)) != OK) {
+                 printf("DS: publish: str copy failed from %d: %d\n",
+                 m_ptr->m_source, r);
+                 return r;
+         }
+         break;
+       default:
+          panic(__FILE__, "Impossible type.", type);
+         break;
   }
 
+  /* If anyone has a matching subscription, update them. */
+  check_subscribers(dsp);
+
   return(OK);
 }
 
 
+/*===========================================================================*
+ *                             do_retrieve                                  *
+ *===========================================================================*/
 PUBLIC int do_retrieve(m_ptr)
 message *m_ptr;                                        /* request message */
 {
   struct data_store *dsp;
+  char key_name[DS_MAX_KEYLEN];
+  int r, type;
+  size_t len;
+
+  if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 1) {
+       printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
+               m_ptr->m_source);
+       return EINVAL;
+  }
+
+  /* Copy name from caller. */
+  if ((r=sys_safecopyfrom(m_ptr->m_source,
+       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0, 
+       (vir_bytes) key_name, m_ptr->DS_KEY_LEN, D)) != OK) {
+       printf("DS: retrieve: copy failed from %d: %d\n", m_ptr->m_source, r);
+       return r;
+  }
+
+  /* Make sure name is 0-terminated. */
+  key_name[DS_MAX_KEYLEN-1] = '\0';
+
 
   /* Retrieve data. Look up the key in the data store. Return an error if it
    * is not found. If this data is private, only the owner may retrieve it.
    */ 
-  if (find_key(m_ptr->DS_KEY, &dsp)) {                 /* look up key */
+  type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
+  if (find_key(key_name, &dsp, type)) {        /* look up key */
+      /* Data is public or the caller is authorized to retrieve it. */
+      switch(type) {
+       case DS_TYPE_U32:
+               m_ptr->DS_VAL = dsp->ds_val.ds_val_u32;  /* return value */
+               break;
+       case DS_TYPE_STR:
+               len = strlen(dsp->ds_val.ds_val_str) + 1;
+               if(len > m_ptr->DS_VAL_LEN)
+                       len = m_ptr->DS_VAL_LEN;
+               if ((r=sys_safecopyto(m_ptr->m_source, m_ptr->DS_VAL,
+                       0, (vir_bytes) dsp->ds_val.ds_val_str,len, D)) != OK) {
+                       printf("DS: retrieve: copy failed to %d: %d\n", 
+                               m_ptr->m_source, r);
+                       return r;
+               }
+               break;
+       default:
+                panic(__FILE__, "retrieve: impossible type.", type);
+               /* not reached. */
+               break;
 
-      /* If the data is not public, the caller must be authorized. */
-      if (! dsp->ds_flags & DS_PUBLIC) {               /* check if private */
-          if (! is_authorized(dsp,m_ptr->DS_AUTH)) {   /* authorize call */
-              return(EPERM);                           /* not allowed */
-          }
       }
-
-      /* Data is public or the caller is authorized to retrieve it. */
-      printf("DS retrieves data: key %d (found %d), l1 %u, l2 %u\n",
-               m_ptr->DS_KEY, dsp->ds_key, dsp->ds_val_l1, dsp->ds_val_l2);
-      m_ptr->DS_VAL_L1 = dsp->ds_val_l1;               /* return value */
-      m_ptr->DS_VAL_L2 = dsp->ds_val_l2;               /* return value */
       return(OK);                                      /* report success */
   }
   return(ESRCH);                                       /* key not found */
 }
 
+/*===========================================================================*
+ *                             do_check                                     *
+ *===========================================================================*/
+PUBLIC int do_check(m_ptr)
+message *m_ptr;                                        /* request message */
+{
+/* This routine goes through all subscriptions for a client,
+ * and checks all data items if it has been flagged (i.e.,
+ * created or updated) matching that subscription. Return
+ * a message and copy the key and value for every one.
+ */
+       struct data_store *dsp;
+       int r, s, d, type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
+       if(!type) return EINVAL;
+       for(s = 0; s < NR_DS_SUBS; s++) {
+               int len;
+               if(!(ds_subs[s].sub_flags & DS_IN_USE))
+                       continue;
+               if(m_ptr->m_source != ds_subs[s].sub_owner)
+                       continue;
+               for(d = 0;  d < NR_DS_KEYS; d++) {
+                       
+                       /* No match if this is no value, it's
+                        * not flagged, or the type is wrong.
+                        */
+
+                       if(!(ds_store[d].ds_flags & DS_IN_USE))
+                               continue;
+                       if(!GET_BIT(ds_store[d].ds_old_subs, s))
+                               continue;
+                       if(type != (ds_store[d].ds_flags & DS_TYPE_MASK))
+                               continue;
+
+                       /* We have a match. Unflag it for this
+                        * subscription.
+                        */
+                       UNSET_BIT(ds_store[d].ds_old_subs, s);
+                       len = strlen(ds_store[d].ds_key)+1;
+                       if(len > m_ptr->DS_KEY_LEN) 
+                               len = m_ptr->DS_KEY_LEN;
+
+                       /* Copy the key into client. */
+                       if ((r=sys_safecopyto(m_ptr->m_source,
+                               (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
+                               (vir_bytes) ds_store[d].ds_key,
+                               len, D)) != OK)
+                               return r;
+
+                       /* Now copy the value. */
+                       switch(type) {
+                               case DS_TYPE_STR:
+                                       len = strlen(ds_store[d].
+                                               ds_val.ds_val_str)+1;
+                                       if(len > m_ptr->DS_VAL_LEN)
+                                               len = m_ptr->DS_VAL_LEN;
+                                       if ((r=sys_safecopyto(m_ptr->m_source,
+                                               m_ptr->DS_VAL, 0,
+                                               (vir_bytes) ds_store[d].
+                                                 ds_val.ds_val_str,
+                                               len, D)) != OK)
+                                               return r;
+                                       break;
+                               case DS_TYPE_U32:
+                                       m_ptr->DS_VAL =
+                                               ds_store[d].ds_val.ds_val_u32;
+                                       break;
+                               default:
+                                       panic(__FILE__,
+                                               "Check impossible type.",
+                                               type);
+                       }
+
+                       return OK;
+               }
+       }
+
+       return(ESRCH);                                  /* key not found */
+}
 
 PUBLIC int do_subscribe(m_ptr)
 message *m_ptr;                                        /* request message */
 {
-  /* Subscribe to a key of interest. Only existing and public keys can be
-   * subscribed to. All updates to the key will cause a notification message
+  char regex[DS_MAX_KEYLEN+3];
+  int s, type, e, d, n = 0;
+  char errbuf[80];
+
+  /* Subscribe to a key of interest.
+   * All updates to the key will cause a notification message
    * to be sent to the subscribed. On success, directly return a copy of the
    * data for the given key. 
    */
-  return(ENOSYS);
+  if(m_ptr->DS_KEY_LEN < 2 || m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN)
+       return EINVAL;
+
+  /* Copy name from caller. Anchor the subscription with "^regexp$" so
+   * substrings don't match. The caller probably will not expect this,
+   * and the usual case is for a complete match.
+   */
+  regex[0] = '^';
+  if ((s=sys_safecopyfrom(m_ptr->m_source,
+       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0, 
+       (vir_bytes) regex + 1, m_ptr->DS_KEY_LEN, D)) != OK) {
+       printf("DS: retrieve: copy failed from %d: %d\n", m_ptr->m_source, s);
+       return s;
+  }
+
+  regex[DS_MAX_KEYLEN-1] = '\0';
+  strcat(regex, "$");
+
+  /* Find subscription slot. */
+  for(s = 0; s < NR_DS_SUBS; s++)
+       if(!(ds_subs[s].sub_flags & DS_IN_USE))
+               break;
+
+  if(s >= NR_DS_SUBS) {
+       printf("DS: no space for subscription by %d.\n", m_ptr->m_source);
+       return ENOSPC;
+  }
+
+  /* Compile regular expression. */
+  if((e=regcomp(&ds_subs[s].sub_regex, regex, REG_EXTENDED)) != 0) {
+       regerror(e, &ds_subs[s].sub_regex, errbuf, sizeof(errbuf));
+       printf("DS: subscribe: regerror: %s\n", errbuf);
+       return EINVAL;
+  }
+  type = (m_ptr->DS_FLAGS & DS_TYPE_MASK);
+  ds_subs[s].sub_flags = DS_IN_USE | type;
+  ds_subs[s].sub_owner = m_ptr->m_source;
+
+  /* Caller requested an instant initial list? */
+  if(m_ptr->DS_FLAGS & DS_INITIAL) {
+       for(d = 0; d < NR_DS_KEYS; d++) {
+         if(!(ds_store[d].ds_flags & DS_IN_USE))
+            continue;
+         if(regexec(&ds_subs[s].sub_regex, ds_store[d].ds_key,
+               0, NULL, 0) == 0) {
+               SET_BIT(ds_store[d].ds_old_subs, s);
+               n = 1;
+         }
+      }
+
+      /* Any matches? */
+      if(n) notify(ds_subs[s].sub_owner);
+   }
+
+   return OK;
 }
 
 
@@ -156,8 +386,34 @@ message *m_ptr;
 
   dst_proc = m_ptr->m_source;
   dst_addr = (vir_bytes) m_ptr->m1_p1;
-  if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)))
+  if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len))) {
+       printf("DS: copy failed: %d\n", s);
        return(s);
+  }
   return(OK);
 }
 
+/*===========================================================================*
+ *                             check_subscribers                            *
+ *===========================================================================*/
+PRIVATE void
+check_subscribers(struct data_store *dsp)
+{
+/* Send subscribers whose subscriptions match this (new
+ * or updated) data item a notify(), and flag the subscriptions
+ * as updated.
+ */
+       int i;
+       for(i = 0; i < NR_DS_SUBS; i++) {
+               if(ds_subs[i].sub_flags & DS_IN_USE) {
+                       if(regexec(&ds_subs[i].sub_regex, dsp->ds_key, 
+                               0, NULL, 0) == 0) {
+                               SET_BIT(dsp->ds_old_subs, i);
+                               notify(ds_subs[i].sub_owner);
+                       } else {
+                               UNSET_BIT(dsp->ds_old_subs, i);
+                       }
+               } 
+       }
+}
+
index 7194318d8783f5d8c9728f67366308e7f481168a..d70d9e59fdfff0dbeafa3c0621c40e7809cf6108 100644 (file)
@@ -1,19 +1,33 @@
 /* Type definitions for the Data Store Server. */
-struct data_store {
-  int ds_flags;                        /* flags for this store */
-  int ds_key;                  /* key to lookup information */
-  long ds_val_l1;              /* data associated with key */
-  long ds_val_l2;              /* data associated with key */
-  long ds_auth;                        /* secret given by owner of data */
-  int ds_nr_subs;              /* number of subscribers for key */ 
-};
 
-/* Flag values. */
-#define DS_IN_USE      0x01
-#define DS_PUBLIC      0x02
+#include <sys/types.h>
+#include <minix/sys_config.h>
+#include <minix/ds.h>
+#include <minix/bitmap.h>
+#include <regex.h>
 
 /* Constants for the Data Store Server. */
-#define NR_DS_KEYS       64    /* reserve space for so many items */
+#define NR_DS_KEYS               64    /* reserve space for so many items */
+#define NR_DS_SUBS   (4*_NR_SYS_PROCS) /* .. and so many subscriptions */
+
+/* Types. */
+
+struct data_store {
+  int ds_flags;                        /* flags for this store, includes type info */
+  char ds_key[DS_MAX_KEYLEN];  /* key to lookup information */
+  union {
+    u32_t ds_val_u32;                  /* u32 data (DS_TYPE_U32) */
+    char  ds_val_str[DS_MAX_VALLEN];   /* string data (DS_TYPE_STR) */
+  } ds_val;
+
+  /* out of date subscribers. */
+  bitchunk_t ds_old_subs[BITMAP_CHUNKS(NR_DS_SUBS)];   
+};
 
+struct subscription {
+  int sub_flags;               /* flags for this subscription */
+  regex_t sub_regex;           /* regular expression agains keys */
+  endpoint_t sub_owner;                /* who is subscribed */
+};
 
 
index 52c7b432d129b93eb1df6089f0b20e16519b29ce..483a9c51c14397afdd63afc5313db16f8bf8e3a9 100644 (file)
@@ -12,7 +12,7 @@
 /* Define hooks for the debugging dumps. This table maps function keys
  * onto a specific dump and provides a description for it.
  */
-#define NHOOKS 19
+#define NHOOKS 18
 
 struct hook_entry {
        int key;
index 4de838537971e4841c14deda126ec0029c23dbd3..27b337eb3db72b9c45a538a5c8e13b6881ae6cb2 100644 (file)
@@ -20,26 +20,32 @@ FORWARD _PROTOTYPE( char *s_flags_str, (int flags)          );
 PUBLIC void data_store_dmp()
 {
   struct data_store *dsp;
-  int i,j, n=0;
+  int i,j, n=0, s;
   static int prev_i=0;
 
 
   printf("Data Store (DS) contents dump\n");
 
-  getsysinfo(DS_PROC_NR, SI_DATA_STORE, store);
+  if((s=getsysinfo(DS_PROC_NR, SI_DATA_STORE, store)) != OK) {
+       printf("Couldn't talk to DS: %d.\n", s);
+       return;
+  }
 
-  printf("-slot- -key- -flags- -val_l1- -val_l2-\n");
+  printf("slot key                  type value\n");
 
   for (i=prev_i; i<NR_DS_KEYS; i++) {
        dsp = &store[i];
        if (! dsp->ds_flags & DS_IN_USE) continue;
        if (++n > 22) break;
-       printf("%3d %8d %s  [%8d] [%8d] \n",
-               i, dsp->ds_key,
-               s_flags_str(dsp->ds_flags),
-               dsp->ds_val_l1,
-               dsp->ds_val_l2
-       );
+       printf("%3d  %-20s ",
+               i, dsp->ds_key);
+       if(dsp->ds_flags & DS_TYPE_U32) {
+               printf("u32  %lu\n", dsp->ds_val.ds_val_u32);
+       } else if(dsp->ds_flags & DS_TYPE_STR) {
+               printf("str  \"%s\"\n", dsp->ds_val.ds_val_str);
+       } else {
+               printf("Bogus type\n");
+       }
   }
   if (i >= NR_DS_KEYS) i = 0;
   else printf("--more--\r");