diff --git a/libc/bionic/system_properties.c b/libc/bionic/system_properties.c index 0587430a5..d96950709 100644 --- a/libc/bionic/system_properties.c +++ b/libc/bionic/system_properties.c @@ -26,6 +26,7 @@ * SUCH DAMAGE. */ #include +#include #include #include #include @@ -49,6 +50,25 @@ #include +struct prop_area { + unsigned volatile count; + unsigned volatile serial; + unsigned magic; + unsigned version; + unsigned reserved[4]; + unsigned toc[1]; +}; + +typedef struct prop_area prop_area; + +struct prop_info { + char name[PROP_NAME_MAX]; + unsigned volatile serial; + char value[PROP_VALUE_MAX]; +}; + +typedef struct prop_info prop_info; + static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME; static unsigned dummy_props = 0; @@ -66,6 +86,17 @@ static int get_fd_from_env(void) return atoi(env); } +void __system_property_area_init(void *data) +{ + prop_area *pa = data; + memset(pa, 0, PA_SIZE); + pa->magic = PROP_AREA_MAGIC; + pa->version = PROP_AREA_VERSION; + + /* plug into the lib property services */ + __system_property_area__ = pa; +} + int __system_properties_init(void) { bool fromFile = true; @@ -147,6 +178,11 @@ const prop_info *__system_property_find(const char *name) unsigned len = strlen(name); prop_info *pi; + if (len >= PROP_NAME_MAX) + return 0; + if (len < 1) + return 0; + while(count--) { unsigned entry = *toc++; if(TOC_NAME_LEN(entry) != len) continue; @@ -294,3 +330,68 @@ int __system_property_wait(const prop_info *pi) } return 0; } + +int __system_property_update(prop_info *pi, const char *value, unsigned int len) +{ + prop_area *pa = __system_property_area__; + + if (len >= PROP_VALUE_MAX) + return -1; + + pi->serial = pi->serial | 1; + memcpy(pi->value, value, len + 1); + pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff); + __futex_wake(&pi->serial, INT32_MAX); + + pa->serial++; + __futex_wake(&pa->serial, INT32_MAX); + + return 0; +} + +int __system_property_add(const char *name, unsigned int namelen, + const char *value, unsigned int valuelen) +{ + prop_area *pa = __system_property_area__; + prop_info *pa_info_array = (void*) (((char*) pa) + PA_INFO_START); + prop_info *pi; + + if (pa->count == PA_COUNT_MAX) + return -1; + if (namelen >= PROP_NAME_MAX) + return -1; + if (valuelen >= PROP_VALUE_MAX) + return -1; + if (namelen < 1) + return -1; + + pi = pa_info_array + pa->count; + pi->serial = (valuelen << 24); + memcpy(pi->name, name, namelen + 1); + memcpy(pi->value, value, valuelen + 1); + + pa->toc[pa->count] = + (namelen << 24) | (((unsigned) pi) - ((unsigned) pa)); + + pa->count++; + pa->serial++; + __futex_wake(&pa->serial, INT32_MAX); + + return 0; +} + +unsigned int __system_property_serial(const prop_info *pi) +{ + return pi->serial; +} + +unsigned int __system_property_wait_any(unsigned int serial) +{ + prop_area *pa = __system_property_area__; + + do { + __futex_wait(&pa->serial, serial, 0); + } while(pa->serial == serial); + + return pa->serial; +} diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h index 5d2043d24..c5bc2235b 100644 --- a/libc/include/sys/_system_properties.h +++ b/libc/include/sys/_system_properties.h @@ -34,7 +34,6 @@ #else #include -typedef struct prop_area prop_area; typedef struct prop_msg prop_msg; #define PROP_AREA_MAGIC 0x504f5250 @@ -43,29 +42,20 @@ typedef struct prop_msg prop_msg; #define PROP_SERVICE_NAME "property_service" #define PROP_FILENAME "/dev/__properties__" -/* #define PROP_MAX_ENTRIES 247 */ -/* 247 -> 32620 bytes (<32768) */ +/* (8 header words + 247 toc words) = 1020 bytes */ +/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */ + +#define PA_COUNT_MAX 247 +#define PA_INFO_START 1024 +#define PA_SIZE 32768 #define TOC_NAME_LEN(toc) ((toc) >> 24) #define TOC_TO_INFO(area, toc) ((prop_info*) (((char*) area) + ((toc) & 0xFFFFFF))) -struct prop_area { - unsigned volatile count; - unsigned volatile serial; - unsigned magic; - unsigned version; - unsigned reserved[4]; - unsigned toc[1]; -}; - #define SERIAL_VALUE_LEN(serial) ((serial) >> 24) #define SERIAL_DIRTY(serial) ((serial) & 1) -struct prop_info { - char name[PROP_NAME_MAX]; - unsigned volatile serial; - char value[PROP_VALUE_MAX]; -}; +__BEGIN_DECLS struct prop_msg { @@ -106,5 +96,47 @@ struct prop_msg #define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop" #define PROP_PATH_FACTORY "/factory/factory.prop" +/* +** Initialize the area to be used to store properties. Can +** only be done by a single process that has write access to +** the property area. +*/ +void __system_property_area_init(void *data); + +/* Add a new system property. Can only be done by a single +** process that has write access to the property area, and +** that process must handle sequencing to ensure the property +** does not already exist and that only one property is added +** or updated at a time. +** +** Returns 0 on success, -1 if the property area is full. +*/ +int __system_property_add(const char *name, unsigned int namelen, + const char *value, unsigned int valuelen); + +/* Update the value of a system property returned by +** __system_property_find. Can only be done by a single process +** that has write access to the property area, and that process +** must handle sequencing to ensure that only one property is +** updated at a time. +** +** Returns 0 on success, -1 if the parameters are incorrect. +*/ +int __system_property_update(prop_info *pi, const char *value, unsigned int len); + +/* Read the serial number of a system property returned by +** __system_property_find. +** +** Returns the serial number on success, -1 on error. +*/ +unsigned int __system_property_serial(const prop_info *pi); + +/* Wait for any system property to be updated. Caller must pass +** in 0 the first time, and the previous return value on each +** successive call. */ +unsigned int __system_property_wait_any(unsigned int serial); + +__END_DECLS + #endif #endif diff --git a/libc/netbsd/resolv/res_state.c b/libc/netbsd/resolv/res_state.c index 32ffdcaf8..de82e1a54 100644 --- a/libc/netbsd/resolv/res_state.c +++ b/libc/netbsd/resolv/res_state.c @@ -71,7 +71,7 @@ _res_thread_alloc(void) rt->_serial = 0; rt->_pi = (struct prop_info*) __system_property_find("net.change"); if (rt->_pi) { - rt->_serial = rt->_pi->serial; + rt->_serial = __system_property_serial(rt->_pi); } memset(rt->_rstatic, 0, sizeof rt->_rstatic); } @@ -135,14 +135,14 @@ _res_thread_get(void) return rt; } } - if (rt->_serial == rt->_pi->serial) { + if (rt->_serial == __system_property_serial(rt->_pi)) { /* Nothing changed, so return the current state */ D("%s: tid=%d rt=%p nothing changed, returning", __FUNCTION__, gettid(), rt); return rt; } /* Update the recorded serial number, and go reset the state */ - rt->_serial = rt->_pi->serial; + rt->_serial = __system_property_serial(rt->_pi); goto RESET_STATE; }