Store objects in wl_map data structure

The wl_map data structure is just an array with a free-list that lets the
client recycle unused client IDs and keep range of client IDs under control.
This commit is contained in:
Kristian Høgsberg 2011-08-19 22:50:53 -04:00
parent 3e0d4de6ea
commit 1f883cc39e
8 changed files with 161 additions and 67 deletions

View file

@ -495,7 +495,7 @@ wl_connection_vmarshal(struct wl_connection *connection,
struct wl_closure * struct wl_closure *
wl_connection_demarshal(struct wl_connection *connection, wl_connection_demarshal(struct wl_connection *connection,
uint32_t size, uint32_t size,
struct wl_hash_table *objects, struct wl_map *objects,
const struct wl_message *message) const struct wl_message *message)
{ {
uint32_t *p, *next, *end, length; uint32_t *p, *next, *end, length;
@ -586,7 +586,7 @@ wl_connection_demarshal(struct wl_connection *connection,
extra += sizeof *object; extra += sizeof *object;
closure->args[i] = object; closure->args[i] = object;
*object = wl_hash_table_lookup(objects, *p); *object = wl_map_lookup(objects, *p);
if (*object == NULL && *p != 0) { if (*object == NULL && *p != 0) {
printf("unknown object (%d), message %s(%s)\n", printf("unknown object (%d), message %s(%s)\n",
*p, message->name, message->signature); *p, message->name, message->signature);
@ -599,7 +599,7 @@ wl_connection_demarshal(struct wl_connection *connection,
case 'n': case 'n':
closure->types[i] = &ffi_type_uint32; closure->types[i] = &ffi_type_uint32;
closure->args[i] = p; closure->args[i] = p;
object = wl_hash_table_lookup(objects, *p); object = wl_map_lookup(objects, *p);
if (*p == 0 || object != NULL) { if (*p == 0 || object != NULL) {
printf("not a new object (%d), " printf("not a new object (%d), "
"message %s(%s)\n", "message %s(%s)\n",

View file

@ -53,7 +53,7 @@ wl_connection_vmarshal(struct wl_connection *connection,
struct wl_closure * struct wl_closure *
wl_connection_demarshal(struct wl_connection *connection, wl_connection_demarshal(struct wl_connection *connection,
uint32_t size, uint32_t size,
struct wl_hash_table *objects, struct wl_map *objects,
const struct wl_message *message); const struct wl_message *message);
void void
wl_closure_invoke(struct wl_closure *closure, wl_closure_invoke(struct wl_closure *closure,

View file

@ -62,9 +62,8 @@ struct wl_display {
struct wl_proxy proxy; struct wl_proxy proxy;
struct wl_connection *connection; struct wl_connection *connection;
int fd; int fd;
uint32_t id;
uint32_t mask; uint32_t mask;
struct wl_hash_table *objects; struct wl_map objects;
struct wl_list global_listener_list; struct wl_list global_listener_list;
struct wl_list global_list; struct wl_list global_list;
@ -133,9 +132,8 @@ wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
proxy->object.interface = interface; proxy->object.interface = interface;
proxy->object.implementation = NULL; proxy->object.implementation = NULL;
proxy->object.id = wl_display_allocate_id(display); proxy->object.id = wl_map_insert_new(&display->objects, proxy);
proxy->display = display; proxy->display = display;
wl_hash_table_insert(display->objects, proxy->object.id, proxy);
return proxy; return proxy;
} }
@ -143,7 +141,7 @@ wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
WL_EXPORT void WL_EXPORT void
wl_proxy_destroy(struct wl_proxy *proxy) wl_proxy_destroy(struct wl_proxy *proxy)
{ {
wl_hash_table_remove(proxy->display->objects, proxy->object.id); wl_map_remove(&proxy->display->objects, proxy->object.id);
free(proxy); free(proxy);
} }
@ -216,10 +214,6 @@ display_handle_global(void *data,
struct wl_global_listener *listener; struct wl_global_listener *listener;
struct wl_global *global; struct wl_global *global;
if (strcmp(interface, "wl_display") == 0)
wl_hash_table_insert(display->objects,
id, &display->proxy.object);
global = malloc(sizeof *global); global = malloc(sizeof *global);
global->id = id; global->id = id;
global->interface = strdup(interface); global->interface = strdup(interface);
@ -324,29 +318,22 @@ wl_display_connect(const char *name)
return NULL; return NULL;
} }
display->objects = wl_hash_table_create(); wl_map_init(&display->objects);
if (display->objects == NULL) {
close(display->fd);
free(display);
return NULL;
}
wl_list_init(&display->global_listener_list); wl_list_init(&display->global_listener_list);
wl_list_init(&display->global_list); wl_list_init(&display->global_list);
display->id = 1; wl_map_insert_new(&display->objects, NULL);
display->proxy.object.interface = &wl_display_interface;
display->proxy.object.id = display->id++;
display->proxy.display = display;
display->proxy.object.implementation = display->proxy.object.interface = &wl_display_interface;
(void(**)(void)) &display_listener; display->proxy.object.id = wl_map_insert_new(&display->objects, display);
display->proxy.display = display;
display->proxy.object.implementation = (void(**)(void)) &display_listener;
display->proxy.user_data = display; display->proxy.user_data = display;
display->connection = wl_connection_create(display->fd, display->connection = wl_connection_create(display->fd,
connection_update, connection_update, display);
display);
if (display->connection == NULL) { if (display->connection == NULL) {
wl_hash_table_destroy(display->objects); wl_map_release(&display->objects);
close(display->fd); close(display->fd);
free(display); free(display);
return NULL; return NULL;
@ -362,7 +349,7 @@ wl_display_destroy(struct wl_display *display)
struct wl_global_listener *listener, *lnext; struct wl_global_listener *listener, *lnext;
wl_connection_destroy(display->connection); wl_connection_destroy(display->connection);
wl_hash_table_destroy(display->objects); wl_map_release(&display->objects);
wl_list_for_each_safe(global, gnext, wl_list_for_each_safe(global, gnext,
&display->global_list, link) &display->global_list, link)
free(global); free(global);
@ -426,7 +413,7 @@ handle_event(struct wl_display *display,
if (id == 1) if (id == 1)
proxy = &display->proxy; proxy = &display->proxy;
else else
proxy = wl_hash_table_lookup(display->objects, id); proxy = wl_map_lookup(&display->objects, id);
if (proxy == NULL || proxy->object.implementation == NULL) { if (proxy == NULL || proxy->object.implementation == NULL) {
wl_connection_consume(display->connection, size); wl_connection_consume(display->connection, size);
@ -435,7 +422,7 @@ handle_event(struct wl_display *display,
message = &proxy->object.interface->events[opcode]; message = &proxy->object.interface->events[opcode];
closure = wl_connection_demarshal(display->connection, closure = wl_connection_demarshal(display->connection,
size, display->objects, message); size, &display->objects, message);
if (closure == NULL) { if (closure == NULL) {
fprintf(stderr, "Error demarshalling event: %m\n"); fprintf(stderr, "Error demarshalling event: %m\n");
@ -494,12 +481,6 @@ wl_display_flush(struct wl_display *display)
wl_display_iterate (display, WL_DISPLAY_WRITABLE); wl_display_iterate (display, WL_DISPLAY_WRITABLE);
} }
WL_EXPORT uint32_t
wl_display_allocate_id(struct wl_display *display)
{
return display->id++;
}
WL_EXPORT void * WL_EXPORT void *
wl_display_bind(struct wl_display *display, wl_display_bind(struct wl_display *display,
uint32_t name, const struct wl_interface *interface) uint32_t name, const struct wl_interface *interface)

View file

@ -61,7 +61,6 @@ struct wl_display *wl_display_connect(const char *name);
void wl_display_destroy(struct wl_display *display); void wl_display_destroy(struct wl_display *display);
int wl_display_get_fd(struct wl_display *display, int wl_display_get_fd(struct wl_display *display,
wl_display_update_func_t update, void *data); wl_display_update_func_t update, void *data);
uint32_t wl_display_allocate_id(struct wl_display *display);
void wl_display_iterate(struct wl_display *display, uint32_t mask); void wl_display_iterate(struct wl_display *display, uint32_t mask);
void wl_display_flush(struct wl_display *display); void wl_display_flush(struct wl_display *display);
void wl_display_roundtrip(struct wl_display *display); void wl_display_roundtrip(struct wl_display *display);

View file

@ -188,7 +188,7 @@ hash_table_search(struct wl_hash_table *ht, uint32_t hash)
WL_EXPORT void WL_EXPORT void
wl_hash_table_for_each(struct wl_hash_table *ht, wl_hash_table_for_each(struct wl_hash_table *ht,
wl_hash_table_func_t func, void *data) wl_iterator_func_t func, void *data)
{ {
struct hash_entry *entry; struct hash_entry *entry;
uint32_t i; uint32_t i;

View file

@ -61,7 +61,7 @@ struct wl_client {
uint32_t id_count; uint32_t id_count;
uint32_t mask; uint32_t mask;
struct wl_list link; struct wl_list link;
struct wl_hash_table *objects; struct wl_map objects;
}; };
struct wl_display { struct wl_display {
@ -154,10 +154,9 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
if (len < size) if (len < size)
break; break;
resource = wl_hash_table_lookup(client->objects, p[0]); resource = wl_map_lookup(&client->objects, p[0]);
if (resource == NULL) { if (resource == NULL) {
wl_client_post_error(client, wl_client_post_error(client, &resource->object,
&client->display->resource.object,
WL_DISPLAY_ERROR_INVALID_OBJECT, WL_DISPLAY_ERROR_INVALID_OBJECT,
"invalid object %d", p[0]); "invalid object %d", p[0]);
wl_connection_consume(connection, size); wl_connection_consume(connection, size);
@ -167,8 +166,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
object = &resource->object; object = &resource->object;
if (opcode >= object->interface->method_count) { if (opcode >= object->interface->method_count) {
wl_client_post_error(client, wl_client_post_error(client, &resource->object,
&client->display->resource.object,
WL_DISPLAY_ERROR_INVALID_METHOD, WL_DISPLAY_ERROR_INVALID_METHOD,
"invalid method %d, object %s@%d", "invalid method %d, object %s@%d",
object->interface->name, object->interface->name,
@ -180,12 +178,11 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
message = &object->interface->methods[opcode]; message = &object->interface->methods[opcode];
closure = wl_connection_demarshal(client->connection, size, closure = wl_connection_demarshal(client->connection, size,
client->objects, message); &client->objects, message);
len -= size; len -= size;
if (closure == NULL && errno == EINVAL) { if (closure == NULL && errno == EINVAL) {
wl_client_post_error(client, wl_client_post_error(client, &resource->object,
&client->display->resource.object,
WL_DISPLAY_ERROR_INVALID_METHOD, WL_DISPLAY_ERROR_INVALID_METHOD,
"invalid arguments for %s@%d.%s", "invalid arguments for %s@%d.%s",
object->interface->name, object->interface->name,
@ -264,9 +261,10 @@ wl_client_create(struct wl_display *display, int fd)
return NULL; return NULL;
} }
client->objects = wl_hash_table_create(); wl_map_init(&client->objects);
if (client->objects == NULL) {
wl_connection_destroy(client->connection); if (wl_map_insert_at(&client->objects, 0, NULL) < 0) {
wl_map_release(&client->objects);
free(client); free(client);
return NULL; return NULL;
} }
@ -284,13 +282,13 @@ wl_client_add_resource(struct wl_client *client,
{ {
resource->client = client; resource->client = client;
wl_list_init(&resource->destroy_listener_list); wl_list_init(&resource->destroy_listener_list);
wl_hash_table_insert(client->objects, resource->object.id, resource); wl_map_insert_at(&client->objects, resource->object.id, resource);
} }
WL_EXPORT void WL_EXPORT void
wl_client_post_no_memory(struct wl_client *client) wl_client_post_no_memory(struct wl_client *client)
{ {
wl_client_post_error(client, &client->display->resource.object, wl_client_post_error(client, &client->display_resource->object,
WL_DISPLAY_ERROR_NO_MEMORY, "no memory"); WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
} }
@ -314,7 +312,7 @@ wl_resource_destroy(struct wl_resource *resource, uint32_t time)
struct wl_client *client = resource->client; struct wl_client *client = resource->client;
destroy_resource(resource, &time); destroy_resource(resource, &time);
wl_hash_table_remove(client->objects, resource->object.id); wl_map_insert_at(&client->objects, resource->object.id, NULL);
} }
WL_EXPORT void WL_EXPORT void
@ -324,8 +322,8 @@ wl_client_destroy(struct wl_client *client)
printf("disconnect from client %p\n", client); printf("disconnect from client %p\n", client);
wl_hash_table_for_each(client->objects, destroy_resource, &time); wl_map_for_each(&client->objects, destroy_resource, &time);
wl_hash_table_destroy(client->objects); wl_map_release(&client->objects);
wl_event_source_remove(client->source); wl_event_source_remove(client->source);
wl_connection_destroy(client->connection); wl_connection_destroy(client->connection);
wl_list_remove(&client->link); wl_list_remove(&client->link);
@ -525,7 +523,7 @@ display_bind(struct wl_client *client,
break; break;
if (&global->link == &display->global_list) if (&global->link == &display->global_list)
wl_client_post_error(client, &client->display->resource.object, wl_client_post_error(client, &resource->object,
WL_DISPLAY_ERROR_INVALID_OBJECT, WL_DISPLAY_ERROR_INVALID_OBJECT,
"invalid global %d", name); "invalid global %d", name);
else else
@ -536,13 +534,12 @@ static void
display_sync(struct wl_client *client, display_sync(struct wl_client *client,
struct wl_resource *resource, uint32_t id) struct wl_resource *resource, uint32_t id)
{ {
struct wl_resource callback; struct wl_resource *callback;
callback.object.interface = &wl_callback_interface; callback = wl_client_add_object(client,
callback.object.id = id; &wl_callback_interface, NULL, id, NULL);
callback.client = client; wl_resource_post_event(callback, WL_CALLBACK_DONE, 0);
wl_resource_destroy(callback, 0);
wl_resource_post_event(&callback, WL_CALLBACK_DONE, 0);
} }
struct wl_display_interface display_interface = { struct wl_display_interface display_interface = {
@ -838,7 +835,11 @@ wl_client_add_object(struct wl_client *client,
resource->destroy = (void *) free; resource->destroy = (void *) free;
wl_list_init(&resource->destroy_listener_list); wl_list_init(&resource->destroy_listener_list);
wl_hash_table_insert(client->objects, resource->object.id, resource); if (wl_map_insert_at(&client->objects, resource->object.id, resource) < 0) {
wl_client_post_no_memory(client);
free(resource);
return NULL;
}
return resource; return resource;
} }
@ -852,6 +853,8 @@ compositor_bind(struct wl_client *client,
resource = wl_client_add_object(client, &wl_compositor_interface, resource = wl_client_add_object(client, &wl_compositor_interface,
compositor->interface, id, compositor); compositor->interface, id, compositor);
if (resource == NULL)
return;
wl_resource_post_event(resource, wl_resource_post_event(resource,
WL_COMPOSITOR_TOKEN_VISUAL, WL_COMPOSITOR_TOKEN_VISUAL,

View file

@ -121,3 +121,101 @@ wl_array_copy(struct wl_array *array, struct wl_array *source)
wl_array_add(array, source->size); wl_array_add(array, source->size);
memcpy(array->data, source->data, source->size); memcpy(array->data, source->data, source->size);
} }
union map_entry {
uintptr_t next;
void *data;
};
WL_EXPORT void
wl_map_init(struct wl_map *map)
{
memset(map, 0, sizeof *map);
}
WL_EXPORT void
wl_map_release(struct wl_map *map)
{
wl_array_release(&map->entries);
}
WL_EXPORT uint32_t
wl_map_insert_new(struct wl_map *map, void *data)
{
union map_entry *start, *entry;
if (map->free_list) {
start = map->entries.data;
entry = &start[map->free_list >> 1];
map->free_list = entry->next;
} else {
entry = wl_array_add(&map->entries, sizeof *entry);
start = map->entries.data;
}
entry->data = data;
return entry - start;
}
WL_EXPORT int
wl_map_insert_at(struct wl_map *map, uint32_t i, void *data)
{
union map_entry *start;
uint32_t count;
/* assert(map->free_list == NULL */
count = map->entries.size / sizeof *start;
if (count < i)
return -1;
if (count == i)
wl_array_add(&map->entries, sizeof *start);
start = map->entries.data;
start[i].data = data;
return 0;
}
WL_EXPORT void
wl_map_remove(struct wl_map *map, uint32_t i)
{
union map_entry *start;
uint32_t count;
start = map->entries.data;
count = map->entries.size / sizeof *start;
start[i].next = map->free_list;
map->free_list = (i << 1) | 1;
}
WL_EXPORT void *
wl_map_lookup(struct wl_map *map, uint32_t i)
{
union map_entry *start;
uint32_t count;
start = map->entries.data;
count = map->entries.size / sizeof *start;
if (i < count && !(start[i].next & 1))
return start[i].data;
return NULL;
}
WL_EXPORT void
wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data)
{
union map_entry *start, *end, *p;
start = map->entries.data;
end = (union map_entry *) ((char *) map->entries.data + map->entries.size);
for (p = start; p < end; p++)
if (p->data && !(p->next & 1))
func(p->data, data);
}

View file

@ -65,7 +65,7 @@ struct wl_object {
uint32_t id; uint32_t id;
}; };
typedef void (*wl_hash_table_func_t)(void *element, void *data); typedef void (*wl_iterator_func_t)(void *element, void *data);
struct wl_hash_table; struct wl_hash_table;
struct wl_hash_table *wl_hash_table_create(void); struct wl_hash_table *wl_hash_table_create(void);
@ -74,7 +74,7 @@ void *wl_hash_table_lookup(struct wl_hash_table *ht, uint32_t hash);
int wl_hash_table_insert(struct wl_hash_table *ht, uint32_t hash, void *data); int wl_hash_table_insert(struct wl_hash_table *ht, uint32_t hash, void *data);
void wl_hash_table_remove(struct wl_hash_table *ht, uint32_t hash); void wl_hash_table_remove(struct wl_hash_table *ht, uint32_t hash);
void wl_hash_table_for_each(struct wl_hash_table *ht, void wl_hash_table_for_each(struct wl_hash_table *ht,
wl_hash_table_func_t func, void *data); wl_iterator_func_t func, void *data);
/** /**
* wl_list - linked list * wl_list - linked list
@ -149,6 +149,19 @@ void wl_array_release(struct wl_array *array);
void *wl_array_add(struct wl_array *array, int size); void *wl_array_add(struct wl_array *array, int size);
void wl_array_copy(struct wl_array *array, struct wl_array *source); void wl_array_copy(struct wl_array *array, struct wl_array *source);
struct wl_map {
struct wl_array entries;
uint32_t free_list;
};
void wl_map_init(struct wl_map *map);
void wl_map_release(struct wl_map *map);
uint32_t wl_map_insert_new(struct wl_map *map, void *data);
int wl_map_insert_at(struct wl_map *map, uint32_t i, void *data);
void wl_map_remove(struct wl_map *map, uint32_t i);
void *wl_map_lookup(struct wl_map *map, uint32_t i);
void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif