get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/41558/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 41558,
    "url": "http://patches.dpdk.org/api/patches/41558/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1f85bec5ac54c3880046e0937ed3ba49ce6ea5fe.1530009564.git.anatoly.burakov@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1f85bec5ac54c3880046e0937ed3ba49ce6ea5fe.1530009564.git.anatoly.burakov@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1f85bec5ac54c3880046e0937ed3ba49ce6ea5fe.1530009564.git.anatoly.burakov@intel.com",
    "date": "2018-06-26T10:53:17",
    "name": "[v2,6/7] ipc: remove IPC thread for async requests",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "9fb5e19845cbd4e21f191421ccd8ca7dc44d1883",
    "submitter": {
        "id": 4,
        "url": "http://patches.dpdk.org/api/people/4/?format=api",
        "name": "Burakov, Anatoly",
        "email": "anatoly.burakov@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1f85bec5ac54c3880046e0937ed3ba49ce6ea5fe.1530009564.git.anatoly.burakov@intel.com/mbox/",
    "series": [
        {
            "id": 238,
            "url": "http://patches.dpdk.org/api/series/238/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=238",
            "date": "2018-06-26T10:53:12",
            "name": "Remove asynchronous IPC thread",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/238/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/41558/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/41558/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id D29771B568;\n\tTue, 26 Jun 2018 12:53:35 +0200 (CEST)",
            "from mga06.intel.com (mga06.intel.com [134.134.136.31])\n\tby dpdk.org (Postfix) with ESMTP id C08C11B4B5\n\tfor <dev@dpdk.org>; Tue, 26 Jun 2018 12:53:23 +0200 (CEST)",
            "from orsmga003.jf.intel.com ([10.7.209.27])\n\tby orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t26 Jun 2018 03:53:22 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga003.jf.intel.com with ESMTP; 26 Jun 2018 03:53:21 -0700",
            "from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com\n\t[10.237.217.45])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tw5QArKe6026451; Tue, 26 Jun 2018 11:53:20 +0100",
            "from sivswdev01.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev01.ir.intel.com with ESMTP id w5QArKCW021224;\n\tTue, 26 Jun 2018 11:53:20 +0100",
            "(from aburakov@localhost)\n\tby sivswdev01.ir.intel.com with LOCAL id w5QArKpu021220;\n\tTue, 26 Jun 2018 11:53:20 +0100"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.51,274,1526367600\"; d=\"scan'208\";a=\"62273536\"",
        "From": "Anatoly Burakov <anatoly.burakov@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "konstantin.ananyev@intel.com, thomas@monjalon.net,\n\tbruce.richardson@intel.com, qi.z.zhang@intel.com,\n\tJianfeng Tan <jianfeng.tan@intel.com>",
        "Date": "Tue, 26 Jun 2018 11:53:17 +0100",
        "Message-Id": "<1f85bec5ac54c3880046e0937ed3ba49ce6ea5fe.1530009564.git.anatoly.burakov@intel.com>",
        "X-Mailer": "git-send-email 1.7.0.7",
        "In-Reply-To": [
            "<cover.1530009564.git.anatoly.burakov@intel.com>",
            "<cover.1530009564.git.anatoly.burakov@intel.com>"
        ],
        "References": [
            "<cover.1530009564.git.anatoly.burakov@intel.com>",
            "<cover.1529071026.git.anatoly.burakov@intel.com>\n\t<cover.1530009564.git.anatoly.burakov@intel.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH v2 6/7] ipc: remove IPC thread for async requests",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Previously, we were using two IPC threads - one to handle messages\nand synchronous requests, and another to handle asynchronous requests.\nTo handle replies for an async request, rte_mp_handle woke up the\nrte_mp_handle_async thread to process through pthread_cond variable.\n\nChange it to handle asynchronous messages within the main IPC thread.\nTo handle timeout events, for each async request which is sent,\nwe set an alarm for it. If its reply is received before timeout,\nwe will cancel the alarm when we handle the reply; otherwise,\nalarm will invoke the async_reply_handle() as the alarm callback.\n\nSigned-off-by: Jianfeng Tan <jianfeng.tan@intel.com>\nSigned-off-by: Anatoly Burakov <anatoly.burakov@intel.com>\nSuggested-by: Thomas Monjalon <thomas@monjalon.net>\n---\n\nNotes:\n    RFC->RFCv2:\n    - Rebased on latest code\n    - Implemented comments to the original RFC\n\n lib/librte_eal/common/eal_common_proc.c | 201 +++++++++---------------\n 1 file changed, 70 insertions(+), 131 deletions(-)",
    "diff": "diff --git a/lib/librte_eal/common/eal_common_proc.c b/lib/librte_eal/common/eal_common_proc.c\nindex 707d8ab30..6f3366403 100644\n--- a/lib/librte_eal/common/eal_common_proc.c\n+++ b/lib/librte_eal/common/eal_common_proc.c\n@@ -20,6 +20,7 @@\n #include <sys/un.h>\n #include <unistd.h>\n \n+#include <rte_alarm.h>\n #include <rte_common.h>\n #include <rte_cycles.h>\n #include <rte_eal.h>\n@@ -94,11 +95,9 @@ TAILQ_HEAD(pending_request_list, pending_request);\n static struct {\n \tstruct pending_request_list requests;\n \tpthread_mutex_t lock;\n-\tpthread_cond_t async_cond;\n } pending_requests = {\n \t.requests = TAILQ_HEAD_INITIALIZER(pending_requests.requests),\n \t.lock = PTHREAD_MUTEX_INITIALIZER,\n-\t.async_cond = PTHREAD_COND_INITIALIZER\n \t/**< used in async requests only */\n };\n \n@@ -106,6 +105,16 @@ static struct {\n static int\n mp_send(struct rte_mp_msg *msg, const char *peer, int type);\n \n+/* for use with alarm callback */\n+static void\n+async_reply_handle(void *arg);\n+\n+/* for use with process_msg */\n+static struct pending_request *\n+async_reply_handle_thread_unsafe(void *arg);\n+\n+static void\n+trigger_async_action(struct pending_request *req);\n \n static struct pending_request *\n find_pending_request(const char *dst, const char *act_name)\n@@ -290,6 +299,8 @@ process_msg(struct mp_msg_internal *m, struct sockaddr_un *s)\n \tRTE_LOG(DEBUG, EAL, \"msg: %s\\n\", msg->name);\n \n \tif (m->type == MP_REP || m->type == MP_IGN) {\n+\t\tstruct pending_request *req = NULL;\n+\n \t\tpthread_mutex_lock(&pending_requests.lock);\n \t\tpending_req = find_pending_request(s->sun_path, msg->name);\n \t\tif (pending_req) {\n@@ -301,11 +312,14 @@ process_msg(struct mp_msg_internal *m, struct sockaddr_un *s)\n \t\t\tif (pending_req->type == REQUEST_TYPE_SYNC)\n \t\t\t\tpthread_cond_signal(&pending_req->sync.cond);\n \t\t\telse if (pending_req->type == REQUEST_TYPE_ASYNC)\n-\t\t\t\tpthread_cond_signal(\n-\t\t\t\t\t&pending_requests.async_cond);\n+\t\t\t\treq = async_reply_handle_thread_unsafe(\n+\t\t\t\t\t\tpending_req);\n \t\t} else\n \t\t\tRTE_LOG(ERR, EAL, \"Drop mp reply: %s\\n\", msg->name);\n \t\tpthread_mutex_unlock(&pending_requests.lock);\n+\n+\t\tif (req != NULL)\n+\t\t\ttrigger_async_action(req);\n \t\treturn;\n \t}\n \n@@ -365,7 +379,6 @@ timespec_cmp(const struct timespec *a, const struct timespec *b)\n }\n \n enum async_action {\n-\tACTION_NONE, /**< don't do anything */\n \tACTION_FREE, /**< free the action entry, but don't trigger callback */\n \tACTION_TRIGGER /**< trigger callback, then free action entry */\n };\n@@ -375,7 +388,7 @@ process_async_request(struct pending_request *sr, const struct timespec *now)\n {\n \tstruct async_request_param *param;\n \tstruct rte_mp_reply *reply;\n-\tbool timeout, received, last_msg;\n+\tbool timeout, last_msg;\n \n \tparam = sr->async.param;\n \treply = &param->user_reply;\n@@ -383,13 +396,6 @@ process_async_request(struct pending_request *sr, const struct timespec *now)\n \t/* did we timeout? */\n \ttimeout = timespec_cmp(&param->end, now) <= 0;\n \n-\t/* did we receive a response? */\n-\treceived = sr->reply_received != 0;\n-\n-\t/* if we didn't time out, and we didn't receive a response, ignore */\n-\tif (!timeout && !received)\n-\t\treturn ACTION_NONE;\n-\n \t/* if we received a response, adjust relevant data and copy mesasge. */\n \tif (sr->reply_received == 1 && sr->reply) {\n \t\tstruct rte_mp_msg *msg, *user_msgs, *tmp;\n@@ -448,120 +454,60 @@ trigger_async_action(struct pending_request *sr)\n \tfree(sr->async.param->user_reply.msgs);\n \tfree(sr->async.param);\n \tfree(sr->request);\n+\tfree(sr);\n }\n \n static struct pending_request *\n-check_trigger(struct timespec *ts)\n+async_reply_handle_thread_unsafe(void *arg)\n {\n-\tstruct pending_request *next, *cur, *trigger = NULL;\n-\n-\tTAILQ_FOREACH_SAFE(cur, &pending_requests.requests, next, next) {\n-\t\tenum async_action action;\n-\t\tif (cur->type != REQUEST_TYPE_ASYNC)\n-\t\t\tcontinue;\n-\n-\t\taction = process_async_request(cur, ts);\n-\t\tif (action == ACTION_FREE) {\n-\t\t\tTAILQ_REMOVE(&pending_requests.requests, cur, next);\n-\t\t\tfree(cur);\n-\t\t} else if (action == ACTION_TRIGGER) {\n-\t\t\tTAILQ_REMOVE(&pending_requests.requests, cur, next);\n-\t\t\ttrigger = cur;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\treturn trigger;\n-}\n-\n-static void\n-wait_for_async_messages(void)\n-{\n-\tstruct pending_request *sr;\n-\tstruct timespec timeout;\n-\tbool timedwait = false;\n-\tbool nowait = false;\n-\tint ret;\n-\n-\t/* scan through the list and see if there are any timeouts that\n-\t * are earlier than our current timeout.\n-\t */\n-\tTAILQ_FOREACH(sr, &pending_requests.requests, next) {\n-\t\tif (sr->type != REQUEST_TYPE_ASYNC)\n-\t\t\tcontinue;\n-\t\tif (!timedwait || timespec_cmp(&sr->async.param->end,\n-\t\t\t\t&timeout) < 0) {\n-\t\t\tmemcpy(&timeout, &sr->async.param->end,\n-\t\t\t\tsizeof(timeout));\n-\t\t\ttimedwait = true;\n-\t\t}\n-\n-\t\t/* sometimes, we don't even wait */\n-\t\tif (sr->reply_received) {\n-\t\t\tnowait = true;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\tif (nowait)\n-\t\treturn;\n-\n-\tdo {\n-\t\tret = timedwait ?\n-\t\t\tpthread_cond_timedwait(\n-\t\t\t\t&pending_requests.async_cond,\n-\t\t\t\t&pending_requests.lock,\n-\t\t\t\t&timeout) :\n-\t\t\tpthread_cond_wait(\n-\t\t\t\t&pending_requests.async_cond,\n-\t\t\t\t&pending_requests.lock);\n-\t} while (ret != 0 && ret != ETIMEDOUT);\n-\n-\t/* we've been woken up or timed out */\n-}\n-\n-static void *\n-async_reply_handle(void *arg __rte_unused)\n-{\n-\tstruct timeval now;\n+\tstruct pending_request *req = (struct pending_request *)arg;\n+\tenum async_action action;\n \tstruct timespec ts_now;\n-\twhile (1) {\n-\t\tstruct pending_request *trigger = NULL;\n+\tstruct timeval now;\n \n-\t\tpthread_mutex_lock(&pending_requests.lock);\n+\tif (gettimeofday(&now, NULL) < 0) {\n+\t\tRTE_LOG(ERR, EAL, \"Cannot get current time\\n\");\n+\t\tgoto no_trigger;\n+\t}\n+\tts_now.tv_nsec = now.tv_usec * 1000;\n+\tts_now.tv_sec = now.tv_sec;\n \n-\t\t/* we exit this function holding the lock */\n-\t\twait_for_async_messages();\n+\taction = process_async_request(req, &ts_now);\n \n-\t\tif (gettimeofday(&now, NULL) < 0) {\n-\t\t\tpthread_mutex_unlock(&pending_requests.lock);\n-\t\t\tRTE_LOG(ERR, EAL, \"Cannot get current time\\n\");\n-\t\t\tbreak;\n+\tTAILQ_REMOVE(&pending_requests.requests, req, next);\n+\n+\tif (rte_eal_alarm_cancel(async_reply_handle, req) < 0) {\n+\t\t/* if we failed to cancel the alarm because it's already in\n+\t\t * progress, don't proceed because otherwise we will end up\n+\t\t * handling the same message twice.\n+\t\t */\n+\t\tif (rte_errno == EINPROGRESS) {\n+\t\t\tRTE_LOG(DEBUG, EAL, \"Request handling is already in progress\\n\");\n+\t\t\tgoto no_trigger;\n \t\t}\n-\t\tts_now.tv_nsec = now.tv_usec * 1000;\n-\t\tts_now.tv_sec = now.tv_sec;\n-\n-\t\tdo {\n-\t\t\ttrigger = check_trigger(&ts_now);\n-\t\t\t/* unlock request list */\n-\t\t\tpthread_mutex_unlock(&pending_requests.lock);\n-\n-\t\t\tif (trigger) {\n-\t\t\t\ttrigger_async_action(trigger);\n-\t\t\t\tfree(trigger);\n-\n-\t\t\t\t/* we've triggered a callback, but there may be\n-\t\t\t\t * more, so lock the list and check again.\n-\t\t\t\t */\n-\t\t\t\tpthread_mutex_lock(&pending_requests.lock);\n-\t\t\t}\n-\t\t} while (trigger);\n+\t\tRTE_LOG(ERR, EAL, \"Failed to cancel alarm\\n\");\n \t}\n \n-\tRTE_LOG(ERR, EAL, \"ERROR: asynchronous requests disabled\\n\");\n-\n+\tif (action == ACTION_TRIGGER)\n+\t\treturn req;\n+no_trigger:\n+\tfree(req);\n \treturn NULL;\n }\n \n+static void\n+async_reply_handle(void *arg)\n+{\n+\tstruct pending_request *req;\n+\n+\tpthread_mutex_lock(&pending_requests.lock);\n+\treq = async_reply_handle_thread_unsafe(arg);\n+\tpthread_mutex_unlock(&pending_requests.lock);\n+\n+\tif (req != NULL)\n+\t\ttrigger_async_action(req);\n+}\n+\n static int\n open_socket_fd(void)\n {\n@@ -624,7 +570,7 @@ rte_mp_channel_init(void)\n {\n \tchar path[PATH_MAX];\n \tint dir_fd;\n-\tpthread_t mp_handle_tid, async_reply_handle_tid;\n+\tpthread_t mp_handle_tid;\n \n \t/* create filter path */\n \tcreate_socket_path(\"*\", path, sizeof(path));\n@@ -671,17 +617,6 @@ rte_mp_channel_init(void)\n \t\treturn -1;\n \t}\n \n-\tif (rte_ctrl_thread_create(&async_reply_handle_tid,\n-\t\t\t\"rte_mp_async\", NULL,\n-\t\t\tasync_reply_handle, NULL) < 0) {\n-\t\tRTE_LOG(ERR, EAL, \"failed to create mp thead: %s\\n\",\n-\t\t\tstrerror(errno));\n-\t\tclose(mp_fd);\n-\t\tclose(dir_fd);\n-\t\tmp_fd = -1;\n-\t\treturn -1;\n-\t}\n-\n \t/* unlock the directory */\n \tflock(dir_fd, LOCK_UN);\n \tclose(dir_fd);\n@@ -853,7 +788,7 @@ rte_mp_sendmsg(struct rte_mp_msg *msg)\n \n static int\n mp_request_async(const char *dst, struct rte_mp_msg *req,\n-\t\tstruct async_request_param *param)\n+\t\tstruct async_request_param *param, const struct timespec *ts)\n {\n \tstruct rte_mp_msg *reply_msg;\n \tstruct pending_request *pending_req, *exist;\n@@ -898,6 +833,13 @@ mp_request_async(const char *dst, struct rte_mp_msg *req,\n \n \tparam->user_reply.nb_sent++;\n \n+\tif (rte_eal_alarm_set(ts->tv_sec * 1000000 + ts->tv_nsec / 1000,\n+\t\t\t      async_reply_handle, pending_req) < 0) {\n+\t\tRTE_LOG(ERR, EAL, \"Fail to set alarm for request %s:%s\\n\",\n+\t\t\tdst, req->name);\n+\t\trte_panic(\"Fix the above shit to properly free all memory\\n\");\n+\t}\n+\n \treturn 0;\n fail:\n \tfree(pending_req);\n@@ -1119,7 +1061,7 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,\n \n \t/* for secondary process, send request to the primary process only */\n \tif (rte_eal_process_type() == RTE_PROC_SECONDARY) {\n-\t\tret = mp_request_async(eal_mp_socket_path(), copy, param);\n+\t\tret = mp_request_async(eal_mp_socket_path(), copy, param, ts);\n \n \t\t/* if we didn't send anything, put dummy request on the queue */\n \t\tif (ret == 0 && reply->nb_sent == 0) {\n@@ -1162,7 +1104,7 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,\n \t\tsnprintf(path, sizeof(path), \"%s/%s\", mp_dir_path,\n \t\t\t ent->d_name);\n \n-\t\tif (mp_request_async(path, copy, param))\n+\t\tif (mp_request_async(path, copy, param, ts))\n \t\t\tret = -1;\n \t}\n \t/* if we didn't send anything, put dummy request on the queue */\n@@ -1171,9 +1113,6 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,\n \t\tdummy_used = true;\n \t}\n \n-\t/* trigger async request thread wake up */\n-\tpthread_cond_signal(&pending_requests.async_cond);\n-\n \t/* finally, unlock the queue */\n \tpthread_mutex_unlock(&pending_requests.lock);\n \n",
    "prefixes": [
        "v2",
        "6/7"
    ]
}