Don't futex_wait spin when setting properties. Wait for socket close.

Depends on init change I8dd685ea

Bug: 4185486
Change-Id: I3e80cecfad8e072973003ec6f93146c5cad369ac
This commit is contained in:
Brad Fitzpatrick 2011-03-30 13:10:04 -07:00
parent 02be15039a
commit bf90b57b44

View file

@ -30,6 +30,7 @@
#include <unistd.h> #include <unistd.h>
#include <stddef.h> #include <stddef.h>
#include <errno.h> #include <errno.h>
#include <poll.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -156,15 +157,17 @@ int __system_property_get(const char *name, char *value)
static int send_prop_msg(prop_msg *msg) static int send_prop_msg(prop_msg *msg)
{ {
struct pollfd pollfds[1];
struct sockaddr_un addr; struct sockaddr_un addr;
socklen_t alen; socklen_t alen;
size_t namelen; size_t namelen;
int s; int s;
int r; int r;
int result = -1;
s = socket(AF_LOCAL, SOCK_STREAM, 0); s = socket(AF_LOCAL, SOCK_STREAM, 0);
if(s < 0) { if(s < 0) {
return -1; return result;
} }
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
@ -175,30 +178,37 @@ static int send_prop_msg(prop_msg *msg)
if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen) < 0)) { if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen) < 0)) {
close(s); close(s);
return -1; return result;
} }
r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0)); r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
if(r == sizeof(prop_msg)) { if(r == sizeof(prop_msg)) {
r = 0; // We successfully wrote to the property server but now we
} else { // wait for the property server to finish its work. It
r = -1; // acknowledges its completion by closing the socket so we
// poll here (on nothing), waiting for the socket to close.
// If you 'adb shell setprop foo bar' you'll see the POLLHUP
// once the socket closes. Out of paranoia we cap our poll
// at 250 ms.
pollfds[0].fd = s;
pollfds[0].events = 0;
r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
result = 0;
}
} }
close(s); close(s);
return r; return result;
} }
int __system_property_set(const char *key, const char *value) int __system_property_set(const char *key, const char *value)
{ {
unsigned old_serial;
volatile unsigned *serial;
prop_msg msg;
int err; int err;
prop_area *pa = __system_property_area__;
int tries = 0; int tries = 0;
int update_seen = 0; int update_seen = 0;
prop_msg msg;
if(key == 0) return -1; if(key == 0) return -1;
if(value == 0) value = ""; if(value == 0) value = "";
@ -210,54 +220,11 @@ int __system_property_set(const char *key, const char *value)
strlcpy(msg.name, key, sizeof msg.name); strlcpy(msg.name, key, sizeof msg.name);
strlcpy(msg.value, value, sizeof msg.value); strlcpy(msg.value, value, sizeof msg.value);
/* Note the system properties serial number before we do our update. */
const prop_info *pi = __system_property_find(key);
if(pi != NULL) {
serial = &pi->serial;
} else {
serial = &pa->serial;
}
old_serial = *serial;
err = send_prop_msg(&msg); err = send_prop_msg(&msg);
if(err < 0) { if(err < 0) {
return err; return err;
} }
/**
* Wait for the shared memory page to be written back and be
* visible in our address space before returning to the caller
* who might reasonably expect subsequent reads to match what was
* just written.
*
* Sleep 5 ms after failed checks and only wait up to a 500 ms
* total, just in case the system property server fails to update
* for whatever reason.
*/
do {
struct timespec timeout;
timeout.tv_sec = 0;
timeout.tv_nsec = 2500000; // 2.5 ms
if(tries++ > 0) {
usleep(2500); // 2.5 ms
}
__futex_wait(serial, old_serial, &timeout);
if(pi != NULL) {
unsigned new_serial = *serial;
/* Waiting on a specific prop_info to be updated. */
if (old_serial != new_serial && !SERIAL_DIRTY(new_serial)) {
update_seen = 1;
}
} else {
/* Waiting for a prop_info to be created. */
const prop_info *new_pi = __system_property_find(key);
if(new_pi != NULL && !SERIAL_DIRTY(new_pi->serial)) {
update_seen = 1;
}
}
} while (!update_seen && tries < 100);
return 0; return 0;
} }