Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision 1fcfc940d5ec6d6e9be0da114b9324a0b30b41c6)
+++ uspace/srv/devmap/devmap.c	(revision 6519d6f5a49b667921f83081e2ebb90b80c86500)
@@ -29,7 +29,7 @@
 /**
  * @defgroup devmap Device mapper.
- * @brief	HelenOS device mapper.
+ * @brief HelenOS device mapper.
  * @{
- */ 
+ */
 
 /** @file
@@ -47,15 +47,22 @@
 #include <ipc/devmap.h>
 
-#define NAME "devmap"
-
+#define NAME  "devmap"
+
+/** Pending lookup structure. */
+typedef struct {
+	link_t link;
+	char *name;              /**< Device name */
+	ipc_callid_t callid;     /**< Call ID waiting for the lookup */
+} pending_req_t;
 
 LIST_INITIALIZE(devices_list);
 LIST_INITIALIZE(drivers_list);
-
-/* order of locking:
- * drivers_list_futex
- * devices_list_futex
- * (devmap_driver_t *)->devices_futex
- * create_handle_futex
+LIST_INITIALIZE(pending_req);
+
+/* Locking order:
+ *  drivers_list_futex
+ *  devices_list_futex
+ *  (devmap_driver_t *)->devices_futex
+ *  create_handle_futex
  **/
 
@@ -64,25 +71,26 @@
 static atomic_t create_handle_futex = FUTEX_INITIALIZER;
 
-
 static int devmap_create_handle(void)
 {
 	static int last_handle = 0;
 	int handle;
-
+	
 	/* TODO: allow reusing old handles after their unregistration
-		and implement some version of LRU algorithm */
+	 * and implement some version of LRU algorithm
+	 */
+	
 	/* FIXME: overflow */
-	futex_down(&create_handle_futex);	
-
+	futex_down(&create_handle_futex);
+	
 	last_handle += 1;
 	handle = last_handle;
-
-	futex_up(&create_handle_futex);	
-
+	
+	futex_up(&create_handle_futex);
+	
 	return handle;
 }
 
 
-/** Initialize device mapper. 
+/** Initialize device mapper.
  *
  *
@@ -91,5 +99,5 @@
 {
 	/* TODO: */
-
+	
 	return EOK;
 }
@@ -100,21 +108,17 @@
 static devmap_device_t *devmap_device_find_name(const char *name)
 {
-	link_t *item;
+	link_t *item = devices_list.next;
 	devmap_device_t *device = NULL;
-
-	item = devices_list.next;
-
+	
 	while (item != &devices_list) {
-
 		device = list_get_instance(item, devmap_device_t, devices);
-		if (0 == strcmp(device->name, name)) {
-			break;
-		}
+		if (0 == strcmp(device->name, name))
+			break;
 		item = item->next;
 	}
-
+	
 	if (item == &devices_list)
 		return NULL;
-
+	
 	device = list_get_instance(item, devmap_device_t, devices);
 	return device;
@@ -122,84 +126,81 @@
 
 /** Find device with given handle.
+ *
  * @todo: use hash table
+ *
  */
 static devmap_device_t *devmap_device_find_handle(int handle)
 {
-	link_t *item;
+	futex_down(&devices_list_futex);
+	
+	link_t *item = (&devices_list)->next;
 	devmap_device_t *device = NULL;
 	
-	futex_down(&devices_list_futex);
-
-	item = (&devices_list)->next;
-
 	while (item != &devices_list) {
-
 		device = list_get_instance(item, devmap_device_t, devices);
-		if (device->handle == handle) {
-			break;
-		}
+		if (device->handle == handle)
+			break;
 		item = item->next;
 	}
-
+	
 	if (item == &devices_list) {
 		futex_up(&devices_list_futex);
 		return NULL;
 	}
-
+	
 	device = list_get_instance(item, devmap_device_t, devices);
 	
 	futex_up(&devices_list_futex);
-
+	
 	return device;
 }
 
 /**
+ *
  * Unregister device and free it. It's assumed that driver's device list is
  * already locked.
+ *
  */
 static int devmap_device_unregister_core(devmap_device_t *device)
 {
-
 	list_remove(&(device->devices));
 	list_remove(&(device->driver_devices));
-
-	free(device->name);	
+	
+	free(device->name);
 	free(device);
-
-
+	
 	return EOK;
 }
 
 /**
+ *
  * Read info about new driver and add it into linked list of registered
  * drivers.
+ *
  */
 static void devmap_driver_register(devmap_driver_t **odriver)
 {
+	*odriver = NULL;
+	
+	ipc_call_t icall;
+	ipc_callid_t iid = async_get_call(&icall);
+	
+	if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
+		ipc_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	devmap_driver_t *driver = (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
+	
+	if (driver == NULL) {
+		ipc_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	/*
+	 * Get driver name
+	 */
+	ipc_callid_t callid;
 	size_t name_size;
-	ipc_callid_t callid;
-	ipc_call_t call;
-	devmap_driver_t *driver;
-	ipc_callid_t iid;
-	ipc_call_t icall;
-
-	*odriver = NULL;
-	
-	iid = async_get_call(&icall);
-
-	if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	} 
-
-	if (NULL ==
-	    (driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {
-		ipc_answer_0(iid, ENOMEM);
-		return;
-	}
-
-	/* 
-	 * Get driver name
-	 */
 	if (!ipc_data_write_receive(&callid, &name_size)) {
 		free(driver);
@@ -208,5 +209,5 @@
 		return;
 	}
-
+	
 	if (name_size > DEVMAP_NAME_MAXLEN) {
 		free(driver);
@@ -215,15 +216,16 @@
 		return;
 	}
-
+	
 	/*
 	 * Allocate buffer for device name.
 	 */
-	if (NULL == (driver->name = (char *)malloc(name_size + 1))) {
+	driver->name = (char *) malloc(name_size + 1);
+	if (driver->name == NULL) {
 		free(driver);
 		ipc_answer_0(callid, ENOMEM);
 		ipc_answer_0(iid, EREFUSED);
 		return;
-	}	
-
+	}
+	
 	/*
 	 * Send confirmation to sender and get data into buffer.
@@ -235,20 +237,21 @@
 		return;
 	}
-
+	
 	driver->name[name_size] = 0;
-
+	
 	/* Initialize futex for list of devices owned by this driver */
 	futex_initialize(&(driver->devices_futex), 1);
-
-	/* 
+	
+	/*
 	 * Initialize list of asociated devices
 	 */
 	list_initialize(&(driver->devices));
-
-	/* 
+	
+	/*
 	 * Create connection to the driver 
 	 */
+	ipc_call_t call;
 	callid = async_get_call(&call);
-
+	
 	if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
 		ipc_answer_0(callid, ENOTSUP);
@@ -259,5 +262,5 @@
 		return;
 	}
-
+	
 	driver->phone = IPC_GET_ARG5(call);
 	
@@ -265,46 +268,46 @@
 	
 	list_initialize(&(driver->drivers));
-
-	futex_down(&drivers_list_futex);	
+	
+	futex_down(&drivers_list_futex);
 	
 	/* TODO:
 	 * check that no driver with name equal to driver->name is registered
 	 */
-
-	/* 
+	
+	/*
 	 * Insert new driver into list of registered drivers
 	 */
 	list_append(&(driver->drivers), &drivers_list);
-	futex_up(&drivers_list_futex);	
+	futex_up(&drivers_list_futex);
 	
 	ipc_answer_0(iid, EOK);
-
+	
 	*odriver = driver;
 }
 
-/** Unregister device driver, unregister all its devices and free driver
+/**
+ * Unregister device driver, unregister all its devices and free driver
  * structure.
+ *
  */
 static int devmap_driver_unregister(devmap_driver_t *driver)
 {
-	devmap_device_t *device;
-
-	if (NULL == driver)
+	if (driver == NULL)
 		return EEXISTS;
 	
-	futex_down(&drivers_list_futex);	
-
+	futex_down(&drivers_list_futex);
+	
 	ipc_hangup(driver->phone);
 	
 	/* remove it from list of drivers */
 	list_remove(&(driver->drivers));
-
+	
 	/* unregister all its devices */
 	
-	futex_down(&devices_list_futex);	
+	futex_down(&devices_list_futex);
 	futex_down(&(driver->devices_futex));
-
+	
 	while (!list_empty(&(driver->devices))) {
-		device = list_get_instance(driver->devices.next,
+		devmap_device_t *device = list_get_instance(driver->devices.next,
 		    devmap_device_t, driver_devices);
 		devmap_device_unregister_core(device);
@@ -312,15 +315,37 @@
 	
 	futex_up(&(driver->devices_futex));
-	futex_up(&devices_list_futex);	
-	futex_up(&drivers_list_futex);	
-
+	futex_up(&devices_list_futex);
+	futex_up(&drivers_list_futex);
+	
 	/* free name and driver */
-	if (NULL != driver->name) {
+	if (NULL != driver->name)
 		free(driver->name);
-	}
-
+	
 	free(driver);
-
+	
 	return EOK;
+}
+
+
+/** Process pending lookup requests */
+static void process_pending_lookup()
+{
+	link_t *cur;
+	
+loop:
+	for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
+		pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
+		
+		const devmap_device_t *dev = devmap_device_find_name(pr->name);
+		if (!dev)
+			continue;
+		
+		ipc_answer_1(pr->callid, EOK, dev->handle);
+		
+		free(pr->name);
+		list_remove(cur);
+		free(pr);
+		goto loop;
+	}
 }
 
@@ -332,21 +357,19 @@
     devmap_driver_t *driver)
 {
+	if (driver == NULL) {
+		ipc_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	/* Create new device entry */
+	devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
+	if (device == NULL) {
+		ipc_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	/* Get device name */
 	ipc_callid_t callid;
 	size_t size;
-	devmap_device_t *device;
-
-	if (NULL == driver) {
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	/* Create new device entry */
-	if (NULL ==
-	    (device = (devmap_device_t *) malloc(sizeof(devmap_device_t)))) {
-		ipc_answer_0(iid, ENOMEM);
-		return;
-	}
-	
-	/* Get device name */
 	if (!ipc_data_write_receive(&callid, &size)) {
 		free(device);
@@ -354,5 +377,5 @@
 		return;
 	}
-
+	
 	if (size > DEVMAP_NAME_MAXLEN) {
 		free(device);
@@ -364,6 +387,6 @@
 	/* +1 for terminating \0 */
 	device->name = (char *) malloc(size + 1);
-
-	if (NULL == device->name) {
+	
+	if (device->name == NULL) {
 		free(device);
 		ipc_answer_0(callid, ENOMEM);
@@ -374,10 +397,10 @@
 	ipc_data_write_finalize(callid, device->name, size);
 	device->name[size] = 0;
-
+	
 	list_initialize(&(device->devices));
 	list_initialize(&(device->driver_devices));
-
-	futex_down(&devices_list_futex);	
-
+	
+	futex_down(&devices_list_futex);
+	
 	/* Check that device with such name is not already registered */
 	if (NULL != devmap_device_find_name(device->name)) {
@@ -389,13 +412,13 @@
 		return;
 	}
-
+	
 	/* Get unique device handle */
-	device->handle = devmap_create_handle(); 
-
+	device->handle = devmap_create_handle();
+	
 	device->driver = driver;
 	
 	/* Insert device into list of all devices  */
 	list_append(&device->devices, &devices_list);
-
+	
 	/* Insert device into list of devices that belog to one driver */
 	futex_down(&device->driver->devices_futex);	
@@ -403,8 +426,10 @@
 	list_append(&device->driver_devices, &device->driver->devices);
 	
-	futex_up(&device->driver->devices_futex);	
-	futex_up(&devices_list_futex);	
-
+	futex_up(&device->driver->devices_futex);
+	futex_up(&devices_list_futex);
+	
 	ipc_answer_1(iid, EOK, device->handle);
+	
+	process_pending_lookup();
 }
 
@@ -416,28 +441,26 @@
 {
 	/* TODO */
-
 	return EOK;
 }
 
 /** Connect client to the device.
+ *
  * Find device driver owning requested device and forward
  * the message to it.
+ *
  */
 static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
 {
-	devmap_device_t *dev;
-	int handle;
-
 	/*
 	 * Get handle from request
 	 */
-	handle = IPC_GET_ARG2(*call);
-	dev = devmap_device_find_handle(handle);
-
+	int handle = IPC_GET_ARG2(*call);
+	devmap_device_t *dev = devmap_device_find_handle(handle);
+	
 	if (NULL == dev) {
 		ipc_answer_0(callid, ENOENT);
 		return;
-	} 
-
+	}
+	
 	ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle),
 	    IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
@@ -445,98 +468,113 @@
 
 /** Find handle for device instance identified by name.
+ *
  * In answer will be send EOK and device handle in arg1 or a error
- * code from errno.h. 
+ * code from errno.h.
+ *
  */
 static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
 {
-	char *name = NULL;
-	size_t name_size;
-	const devmap_device_t *dev;
-	ipc_callid_t callid;
-	ipcarg_t retval;
-	
-	/* 
+	/*
 	 * Wait for incoming message with device name (but do not
 	 * read the name itself until the buffer is allocated).
 	 */
-	if (!ipc_data_write_receive(&callid, &name_size)) {
+	ipc_callid_t callid;
+	size_t size;
+	if (!ipc_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EREFUSED);
 		ipc_answer_0(iid, EREFUSED);
 		return;
 	}
-
-	if (name_size > DEVMAP_NAME_MAXLEN) {
+	
+	if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(iid, EREFUSED);
 		return;
 	}
-
+	
 	/*
 	 * Allocate buffer for device name.
 	 */
-	if (NULL == (name = (char *)malloc(name_size))) {
+	char *name = (char *) malloc(size);
+	if (name == NULL) {
 		ipc_answer_0(callid, ENOMEM);
 		ipc_answer_0(iid, EREFUSED);
 		return;
-	}	
-
+	}
+	
 	/*
 	 * Send confirmation to sender and get data into buffer.
 	 */
-	if (EOK != (retval = ipc_data_write_finalize(callid, name,
-	    name_size))) {
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-
+	ipcarg_t retval = ipc_data_write_finalize(callid, name, size);
+	if (retval != EOK) {
+		ipc_answer_0(iid, EREFUSED);
+		free(name);
+		return;
+	}
+	name[size] = '\0';
+	
 	/*
 	 * Find device name in linked list of known devices.
 	 */
-	dev = devmap_device_find_name(name);
-
+	const devmap_device_t *dev = devmap_device_find_name(name);
+	
 	/*
 	 * Device was not found.
 	 */
-	if (NULL == dev) {
+	if (dev == NULL) {
+		if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
+			/* Blocking lookup, add to pending list */
+			pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t));
+			if (!pr) {
+				ipc_answer_0(iid, ENOMEM);
+				free(name);
+				return;
+			}
+			
+			pr->name = name;
+			pr->callid = iid;
+			list_append(&pr->link, &pending_req);
+			return;
+		}
+		
 		ipc_answer_0(iid, ENOENT);
-		return;
-	}
-
+		free(name);
+		return;
+	}
+	
 	ipc_answer_1(iid, EOK, dev->handle);
-}
-
-/** Find name of device identified by id and send it to caller. 
+	free(name);
+}
+
+/** Find name of device identified by id and send it to caller.
  *
  */
 static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall) 
 {
-	const devmap_device_t *device;
-	size_t name_size;
-
-	device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
-
+	const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
+	
 	/*
 	 * Device not found.
 	 */
-	if (NULL == device) {
+	if (device == NULL) {
 		ipc_answer_0(iid, ENOENT);
 		return;
-	}	
-
+	}
+	
 	ipc_answer_0(iid, EOK);
-
-	name_size = strlen(device->name);
-
-
-/*	FIXME:
-	we have no channel from DEVMAP to client -> 
-	sending must be initiated by client
-
-	int rc = ipc_data_write_send(phone, device->name, name_size); 
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		return rc;
-	}
-*/	
+	
+	size_t name_size = strlen(device->name);
+	
+	/* FIXME:
+	 * We have no channel from DEVMAP to client, therefore
+	 * sending must be initiated by client.
+	 *
+	 * int rc = ipc_data_write_send(phone, device->name, name_size);
+	 * if (rc != EOK) {
+	 *     async_wait_for(req, NULL);
+	 *     return rc;
+	 * }
+	 */
+	
 	/* TODO: send name in response */
 }
@@ -547,29 +585,28 @@
 static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
 {
-	ipc_callid_t callid;
-	ipc_call_t call;
+	/* Accept connection */
+	ipc_answer_0(iid, EOK);
+	
+	devmap_driver_t *driver = NULL; 
+	devmap_driver_register(&driver);
+	
+	if (NULL == driver)
+		return;
+	
 	bool cont = true;
-	devmap_driver_t *driver = NULL; 
-
-	ipc_answer_0(iid, EOK); 
-
-	devmap_driver_register(&driver);
-
-	if (NULL == driver)
-		return;
-	
 	while (cont) {
-		callid = async_get_call(&call);
-
- 		switch (IPC_GET_METHOD(call)) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		switch (IPC_GET_METHOD(call)) {
 		case IPC_M_PHONE_HUNGUP:
 			cont = false;
-			continue; /* Exit thread */
+			/* Exit thread */
+			continue;
 		case DEVMAP_DRIVER_UNREGISTER:
-			if (NULL == driver) {
+			if (NULL == driver)
 				ipc_answer_0(callid, ENOENT);
-			} else {
+			else
 				ipc_answer_0(callid, EOK);
-			}
 			break;
 		case DEVMAP_DEVICE_REGISTER:
@@ -588,12 +625,11 @@
 			break;
 		default:
-			if (!(callid & IPC_CALLID_NOTIFICATION)) {
+			if (!(callid & IPC_CALLID_NOTIFICATION))
 				ipc_answer_0(callid, ENOENT);
-			}
 		}
 	}
 	
 	if (NULL != driver) {
-		/* 
+		/*
 		 * Unregister the device driver and all its devices.
 		 */
@@ -601,5 +637,4 @@
 		driver = NULL;
 	}
-	
 }
 
@@ -609,21 +644,19 @@
 static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
 {
-	ipc_callid_t callid;
-	ipc_call_t call;
+	/* Accept connection */
+	ipc_answer_0(iid, EOK);
+	
 	bool cont = true;
-
-	ipc_answer_0(iid, EOK); /* Accept connection */
-
 	while (cont) {
-		callid = async_get_call(&call);
-
- 		switch (IPC_GET_METHOD(call)) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		switch (IPC_GET_METHOD(call)) {
 		case IPC_M_PHONE_HUNGUP:
 			cont = false;
-			continue; /* Exit thread */
-
+			/* Exit thread */
+			continue;
 		case DEVMAP_DEVICE_GET_HANDLE:
- 			devmap_get_handle(callid, &call);
-
+			devmap_get_handle(callid, &call);
 			break;
 		case DEVMAP_DEVICE_GET_NAME:
@@ -632,12 +665,11 @@
 			break;
 		default:
-			if (!(callid & IPC_CALLID_NOTIFICATION)) {
+			if (!(callid & IPC_CALLID_NOTIFICATION))
 				ipc_answer_0(callid, ENOENT);
-			}
 		}
 	}
 }
 
-/** Function for handling connections to devmap 
+/** Function for handling connections to devmap
  *
  */
@@ -657,8 +689,7 @@
 		break;
 	default:
-		ipc_answer_0(iid, ENOENT); /* No such interface */
-	}
-
-	/* Cleanup */
+		/* No such interface */
+		ipc_answer_0(iid, ENOENT); 
+	}
 }
 
@@ -670,6 +701,4 @@
 	printf(NAME ": HelenOS Device Mapper\n");
 	
-	ipcarg_t phonead;
-
 	if (devmap_init() != 0) {
 		printf(NAME ": Error while initializing service\n");
@@ -679,6 +708,7 @@
 	/* Set a handler of incomming connections */
 	async_set_client_connection(devmap_connection);
-
+	
 	/* Register device mapper at naming service */
+	ipcarg_t phonead;
 	if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0) 
 		return -1;
@@ -686,4 +716,5 @@
 	printf(NAME ": Accepting connections\n");
 	async_manager();
+	
 	/* Never reached */
 	return 0;
