client: extend error handling
When an error occurs, wl_display_get_error() does not provide any way of getting know if it was a local error or if it was an error event, respectively what object caused the error and what the error was. This patch introduces a new function wl_display_get_protocol_error() which will return error code, interface and id of the object that generated the error. wl_display_get_error() will work the same way as before. wl_display_get_protocol_error() DOES NOT indicate that a non-protocol error happened. It returns valid information only in that case that (protocol) error occurred, so it should be used after calling wl_display_get_error() with positive result. [Pekka Paalanen] Applied another hunk of Bryce's comments to docs, added libtool version bump. Reviewed-by: Pekka Paalanen <ppaalanen@gmail.com> Reviewed-by: Bryce Harrington <b.harrington@samsung.com>
This commit is contained in:
parent
567977815a
commit
886b09c9a3
|
@ -51,7 +51,7 @@ nodist_libwayland_server_la_SOURCES = \
|
|||
|
||||
libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(GCC_CFLAGS) -pthread
|
||||
libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt -lm
|
||||
libwayland_client_la_LDFLAGS = -version-info 2:0:2
|
||||
libwayland_client_la_LDFLAGS = -version-info 3:0:3
|
||||
libwayland_client_la_SOURCES = \
|
||||
src/wayland-client.c
|
||||
|
||||
|
|
|
@ -78,7 +78,24 @@ struct wl_event_queue {
|
|||
struct wl_display {
|
||||
struct wl_proxy proxy;
|
||||
struct wl_connection *connection;
|
||||
|
||||
/* errno of the last wl_display error */
|
||||
int last_error;
|
||||
|
||||
/* When display gets an error event from some object, it stores
|
||||
* information about it here, so that client can get this
|
||||
* information afterwards */
|
||||
struct {
|
||||
/* Code of the error. It can be compared to
|
||||
* the interface's errors enumeration. */
|
||||
uint32_t code;
|
||||
/* interface (protocol) in which the error occurred */
|
||||
const struct wl_interface *interface;
|
||||
/* id of the proxy that caused the error. There's no warranty
|
||||
* that the proxy is still valid. It's up to client how it will
|
||||
* use it */
|
||||
uint32_t id;
|
||||
} protocol_error;
|
||||
int fd;
|
||||
pthread_t display_thread;
|
||||
struct wl_map objects;
|
||||
|
@ -96,6 +113,14 @@ struct wl_display {
|
|||
|
||||
static int debug_client = 0;
|
||||
|
||||
/**
|
||||
* This function is called for local errors (no memory, server hung up)
|
||||
*
|
||||
* \param display
|
||||
* \param error error value (EINVAL, EFAULT, ...)
|
||||
*
|
||||
* \note this function is called with display mutex locked
|
||||
*/
|
||||
static void
|
||||
display_fatal_error(struct wl_display *display, int error)
|
||||
{
|
||||
|
@ -105,7 +130,7 @@ display_fatal_error(struct wl_display *display, int error)
|
|||
return;
|
||||
|
||||
if (!error)
|
||||
error = 1;
|
||||
error = EFAULT;
|
||||
|
||||
display->last_error = error;
|
||||
|
||||
|
@ -113,11 +138,56 @@ display_fatal_error(struct wl_display *display, int error)
|
|||
pthread_cond_broadcast(&iter->cond);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called for error events
|
||||
* and indicates that in some object an error occured.
|
||||
* Difference between this function and display_fatal_error()
|
||||
* is that this one handles errors that will come by wire,
|
||||
* whereas display_fatal_error() is called for local errors.
|
||||
*
|
||||
* \param display
|
||||
* \param code error code
|
||||
* \param id id of the object that generated the error
|
||||
* \param intf protocol interface
|
||||
*/
|
||||
static void
|
||||
wl_display_fatal_error(struct wl_display *display, int error)
|
||||
display_protocol_error(struct wl_display *display, uint32_t code,
|
||||
uint32_t id, const struct wl_interface *intf)
|
||||
{
|
||||
struct wl_event_queue *iter;
|
||||
int err;
|
||||
|
||||
if (display->last_error)
|
||||
return;
|
||||
|
||||
/* set correct errno */
|
||||
if (wl_interface_equal(intf, &wl_display_interface)) {
|
||||
switch (code) {
|
||||
case WL_DISPLAY_ERROR_INVALID_OBJECT:
|
||||
case WL_DISPLAY_ERROR_INVALID_METHOD:
|
||||
err = EINVAL;
|
||||
break;
|
||||
case WL_DISPLAY_ERROR_NO_MEMORY:
|
||||
err = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
err = EFAULT;
|
||||
}
|
||||
} else {
|
||||
err = EPROTO;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&display->mutex);
|
||||
display_fatal_error(display, error);
|
||||
|
||||
display->last_error = err;
|
||||
|
||||
display->protocol_error.code = code;
|
||||
display->protocol_error.id = id;
|
||||
display->protocol_error.interface = intf;
|
||||
|
||||
wl_list_for_each(iter, &display->event_queue_list, link)
|
||||
pthread_cond_broadcast(&iter->cond);
|
||||
|
||||
pthread_mutex_unlock(&display->mutex);
|
||||
}
|
||||
|
||||
|
@ -579,25 +649,12 @@ display_handle_error(void *data,
|
|||
uint32_t code, const char *message)
|
||||
{
|
||||
struct wl_proxy *proxy = object;
|
||||
int err;
|
||||
|
||||
wl_log("%s@%u: error %d: %s\n",
|
||||
proxy->object.interface->name, proxy->object.id, code, message);
|
||||
|
||||
switch (code) {
|
||||
case WL_DISPLAY_ERROR_INVALID_OBJECT:
|
||||
case WL_DISPLAY_ERROR_INVALID_METHOD:
|
||||
err = EINVAL;
|
||||
break;
|
||||
case WL_DISPLAY_ERROR_NO_MEMORY:
|
||||
err = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
err = EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
wl_display_fatal_error(display, err);
|
||||
display_protocol_error(display, code, proxy->object.id,
|
||||
proxy->object.interface);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1486,6 +1543,50 @@ wl_display_get_error(struct wl_display *display)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the information about a protocol error:
|
||||
*
|
||||
* \param display The Wayland display
|
||||
* \param interface if not NULL, stores the interface where the error occurred
|
||||
* \param id if not NULL, stores the object id that generated
|
||||
* the error. There's no guarantee the object is
|
||||
* still valid; the client must know if it deleted the object.
|
||||
* \return The error code as defined in the interface specification.
|
||||
*
|
||||
* \code
|
||||
* int err = wl_display_get_error(display);
|
||||
*
|
||||
* if (err == EPROTO) {
|
||||
* code = wl_display_get_protocol_error(display, &interface, &id);
|
||||
* handle_error(code, interface, id);
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* \endcode
|
||||
*/
|
||||
WL_EXPORT uint32_t
|
||||
wl_display_get_protocol_error(struct wl_display *display,
|
||||
const struct wl_interface **interface,
|
||||
uint32_t *id)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
pthread_mutex_lock(&display->mutex);
|
||||
|
||||
ret = display->protocol_error.code;
|
||||
|
||||
if (interface)
|
||||
*interface = display->protocol_error.interface;
|
||||
if (id)
|
||||
*id = display->protocol_error.id;
|
||||
|
||||
pthread_mutex_unlock(&display->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/** Send all buffered requests on the display to the server
|
||||
*
|
||||
* \param display The display context object
|
||||
|
|
|
@ -161,6 +161,9 @@ int wl_display_dispatch_queue_pending(struct wl_display *display,
|
|||
struct wl_event_queue *queue);
|
||||
int wl_display_dispatch_pending(struct wl_display *display);
|
||||
int wl_display_get_error(struct wl_display *display);
|
||||
uint32_t wl_display_get_protocol_error(struct wl_display *display,
|
||||
const struct wl_interface **interface,
|
||||
uint32_t *id);
|
||||
|
||||
int wl_display_flush(struct wl_display *display);
|
||||
int wl_display_roundtrip(struct wl_display *display);
|
||||
|
|
Loading…
Reference in New Issue
Block a user