From: Ben Gras Date: Thu, 13 Jul 2006 14:50:23 +0000 (+0000) Subject: . DS understands publishing and subscribing where keys are in string X-Git-Tag: v3.1.3~251 X-Git-Url: http://zhaoyanbai.com/repos/man.genrandom.html?a=commitdiff_plain;h=3512a86b445fafbed8c18fb11bb55de2519baf0b;p=minix.git . DS understands publishing and subscribing where keys are in string 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_ retrieve functions are ds_retrieve_ (one-time retrieval of a value) check functions are ds_check_ (check for updated key caller subscribes to not yet checked for, or ESRCH for none) . ramdisk driver updated with new ds interface --- diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index 35b566e95..906699e8a 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -17,10 +17,14 @@ #include "../drivers.h" #include "../libdriver/driver.h" #include +#include #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 #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, diff --git a/include/minix/com.h b/include/minix/com.h index 687598da0..cbc595182 100755 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -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 @@ -548,14 +549,18 @@ #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 * diff --git a/lib/syslib/Makefile.in b/lib/syslib/Makefile.in index da50d08dc..63c0b14e3 100644 --- a/lib/syslib/Makefile.in +++ b/lib/syslib/Makefile.in @@ -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 index 000000000..d2b369641 --- /dev/null +++ b/lib/syslib/ds.c @@ -0,0 +1,259 @@ + +#include +#include + +#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; +} + diff --git a/lib/syslib/safecopies.c b/lib/syslib/safecopies.c index 0559f976f..468c98d77 100644 --- a/lib/syslib/safecopies.c +++ b/lib/syslib/safecopies.c @@ -310,3 +310,4 @@ cp_grant_id_t gid; return 0; } + diff --git a/servers/ds/main.c b/servers/ds/main.c index d90c994cf..ee76f0c31 100644 --- a/servers/ds/main.c +++ b/servers/ds/main.c @@ -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(); } /*===========================================================================* diff --git a/servers/ds/proto.h b/servers/ds/proto.h index cb0a86a94..e5d1435de 100644 --- a/servers/ds/proto.h +++ b/servers/ds/proto.h @@ -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)); diff --git a/servers/ds/store.c b/servers/ds/store.c index c557145d4..86018ee26 100644 --- a/servers/ds/store.c +++ b/servers/ds/store.c @@ -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; iDS_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); + } + } + } +} + diff --git a/servers/ds/store.h b/servers/ds/store.h index 7194318d8..d70d9e59f 100644 --- a/servers/ds/store.h +++ b/servers/ds/store.h @@ -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 +#include +#include +#include +#include /* 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 */ +}; diff --git a/servers/is/dmp.c b/servers/is/dmp.c index 52c7b432d..483a9c51c 100644 --- a/servers/is/dmp.c +++ b/servers/is/dmp.c @@ -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; diff --git a/servers/is/dmp_ds.c b/servers/is/dmp_ds.c index 4de838537..27b337eb3 100644 --- a/servers/is/dmp_ds.c +++ b/servers/is/dmp_ds.c @@ -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; ids_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");