Skip to content

Commit

Permalink
fw_node: process read events recursively
Browse files Browse the repository at this point in the history
The character device driver in Linux FireWire subsystem can consume
given buffer for queued events at one time. It's better to process
the read data recursively.
  • Loading branch information
takaswie committed May 29, 2020
1 parent 933ada2 commit ba3af10
Showing 1 changed file with 48 additions and 29 deletions.
77 changes: 48 additions & 29 deletions src/fw_node.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,8 @@ static gboolean dispatch_src(GSource *gsrc, GSourceFunc cb, gpointer user_data)
FwNodeSource *src = (FwNodeSource *)gsrc;
HinawaFwNodePrivate *priv;
GIOCondition condition;
struct fw_cdev_event_common *common;
GError *exception = NULL;
ssize_t len;
guint8 *buf;

priv = hinawa_fw_node_get_instance_private(src->self);
if (priv->fd < 0)
Expand All @@ -381,35 +380,55 @@ static gboolean dispatch_src(GSource *gsrc, GSourceFunc cb, gpointer user_data)
return G_SOURCE_REMOVE;
}

common = (struct fw_cdev_event_common *)src->buf;

if (HINAWA_IS_FW_NODE(common->closure) &&
common->type == FW_CDEV_EVENT_BUS_RESET)
handle_update(src->self, &exception);
else if (HINAWA_IS_FW_RESP(common->closure) &&
common->type == FW_CDEV_EVENT_REQUEST2)
hinawa_fw_resp_handle_request(HINAWA_FW_RESP(common->closure),
(struct fw_cdev_event_request2 *)common);
else if (HINAWA_IS_FW_REQ(common->closure) &&
common->type == FW_CDEV_EVENT_RESPONSE) {
struct fw_cdev_event_response *ev =
(struct fw_cdev_event_response *)common;
HinawaFwReq *req = HINAWA_FW_REQ(ev->closure);
GList *entry;

// Don't process request invalidated in advance.
g_mutex_lock(&priv->transactions_mutex);
entry = g_list_find(priv->transactions, req);
if (entry) {
priv->transactions =
g_list_delete_link(priv->transactions, entry);
hinawa_fw_req_handle_response(req, ev);
buf = src->buf;
while (len > 0) {
union fw_cdev_event *ev = (union fw_cdev_event *)buf;
size_t size = 0;

switch (ev->common.type) {
case FW_CDEV_EVENT_BUS_RESET:
if (HINAWA_IS_FW_NODE(ev->bus_reset.closure)) {
GError *exception = NULL;
handle_update(src->self, &exception);
if (exception != NULL)
return G_SOURCE_REMOVE;
}
size = sizeof(ev->bus_reset);
break;
case FW_CDEV_EVENT_REQUEST2:
if (HINAWA_IS_FW_RESP(ev->request2.closure)) {
hinawa_fw_resp_handle_request(
HINAWA_FW_RESP(ev->request2.closure),
&ev->request2);
}
size = sizeof(ev->request2) + ev->request2.length;
break;
case FW_CDEV_EVENT_RESPONSE:
if (HINAWA_IS_FW_REQ(ev->response.closure)) {
HinawaFwReq *req =
HINAWA_FW_REQ(ev->response.closure);
GList *entry;

// Don't process request invalidated in advance.
g_mutex_lock(&priv->transactions_mutex);
entry = g_list_find(priv->transactions, req);
if (entry) {
priv->transactions =
g_list_delete_link(priv->transactions,
entry);
hinawa_fw_req_handle_response(req, &ev->response);
}
g_mutex_unlock(&priv->transactions_mutex);
}
size = sizeof(ev->response) + ev->response.length;
break;
default:
break;
}
g_mutex_unlock(&priv->transactions_mutex);
}

if (exception != NULL)
return G_SOURCE_REMOVE;
len -= size;
buf += size;
}

// Just be sure to continue to process this source.
return G_SOURCE_CONTINUE;
Expand Down

0 comments on commit ba3af10

Please sign in to comment.