LCOV - code coverage report
Current view: top level - lib/event - app_rpc.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 384 0.0 %
Date: 2024-12-13 04:08:15 Functions: 0 37 0.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2016 Intel Corporation. All rights reserved.
       3             :  *   Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
       4             :  */
       5             : 
       6             : #include "spdk/stdinc.h"
       7             : 
       8             : #include "spdk/event.h"
       9             : #include "spdk/rpc.h"
      10             : #include "spdk/string.h"
      11             : #include "spdk/util.h"
      12             : #include "spdk/env.h"
      13             : #include "spdk/scheduler.h"
      14             : #include "spdk/thread.h"
      15             : #include "spdk/json.h"
      16             : 
      17             : #include "spdk/log.h"
      18             : #include "spdk_internal/event.h"
      19             : #include "spdk_internal/thread.h"
      20             : #include "event_internal.h"
      21             : 
      22             : struct rpc_spdk_kill_instance {
      23             :         char *sig_name;
      24             : };
      25             : 
      26             : static void
      27           0 : free_rpc_spdk_kill_instance(struct rpc_spdk_kill_instance *req)
      28             : {
      29           0 :         free(req->sig_name);
      30           0 : }
      31             : 
      32             : static const struct spdk_json_object_decoder rpc_spdk_kill_instance_decoders[] = {
      33             :         {"sig_name", offsetof(struct rpc_spdk_kill_instance, sig_name), spdk_json_decode_string},
      34             : };
      35             : 
      36             : static void
      37           0 : rpc_spdk_kill_instance(struct spdk_jsonrpc_request *request,
      38             :                        const struct spdk_json_val *params)
      39             : {
      40             :         static const struct {
      41             :                 const char      *signal_string;
      42             :                 int32_t         signal;
      43             :         } signals[] = {
      44             :                 {"SIGINT",    SIGINT},
      45             :                 {"SIGTERM",   SIGTERM},
      46             :                 {"SIGQUIT",   SIGQUIT},
      47             :                 {"SIGHUP",    SIGHUP},
      48             :                 {"SIGKILL",   SIGKILL},
      49             :                 {"SIGUSR1",   SIGUSR1},
      50             :         };
      51             :         size_t i, sig_count;
      52             :         int signal;
      53           0 :         struct rpc_spdk_kill_instance req = {};
      54             : 
      55           0 :         if (spdk_json_decode_object(params, rpc_spdk_kill_instance_decoders,
      56             :                                     SPDK_COUNTOF(rpc_spdk_kill_instance_decoders),
      57             :                                     &req)) {
      58           0 :                 SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n");
      59           0 :                 goto invalid;
      60             :         }
      61             : 
      62           0 :         sig_count = SPDK_COUNTOF(signals);
      63           0 :         signal = spdk_strtol(req.sig_name, 10);
      64           0 :         for (i = 0 ; i < sig_count; i++) {
      65           0 :                 if (strcmp(req.sig_name, signals[i].signal_string) == 0 ||
      66           0 :                     signal == signals[i].signal) {
      67             :                         break;
      68             :                 }
      69             :         }
      70             : 
      71           0 :         if (i == sig_count) {
      72           0 :                 goto invalid;
      73             :         }
      74             : 
      75           0 :         SPDK_DEBUGLOG(app_rpc, "sending signal %d\n", signals[i].signal);
      76           0 :         free_rpc_spdk_kill_instance(&req);
      77           0 :         kill(getpid(), signals[i].signal);
      78             : 
      79           0 :         spdk_jsonrpc_send_bool_response(request, true);
      80           0 :         return;
      81             : 
      82           0 : invalid:
      83           0 :         spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
      84           0 :         free_rpc_spdk_kill_instance(&req);
      85             : }
      86           0 : SPDK_RPC_REGISTER("spdk_kill_instance", rpc_spdk_kill_instance, SPDK_RPC_RUNTIME)
      87             : 
      88             : 
      89             : struct rpc_framework_monitor_context_switch {
      90             :         bool enabled;
      91             : };
      92             : 
      93             : static const struct spdk_json_object_decoder rpc_framework_monitor_context_switch_decoders[] = {
      94             :         {"enabled", offsetof(struct rpc_framework_monitor_context_switch, enabled), spdk_json_decode_bool},
      95             : };
      96             : 
      97             : static void
      98           0 : rpc_framework_monitor_context_switch(struct spdk_jsonrpc_request *request,
      99             :                                      const struct spdk_json_val *params)
     100             : {
     101           0 :         struct rpc_framework_monitor_context_switch req = {};
     102             :         struct spdk_json_write_ctx *w;
     103             : 
     104           0 :         if (params != NULL) {
     105           0 :                 if (spdk_json_decode_object(params, rpc_framework_monitor_context_switch_decoders,
     106             :                                             SPDK_COUNTOF(rpc_framework_monitor_context_switch_decoders),
     107             :                                             &req)) {
     108           0 :                         SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n");
     109           0 :                         spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
     110           0 :                         return;
     111             :                 }
     112             : 
     113           0 :                 spdk_framework_enable_context_switch_monitor(req.enabled);
     114             :         }
     115             : 
     116           0 :         w = spdk_jsonrpc_begin_result(request);
     117           0 :         spdk_json_write_object_begin(w);
     118             : 
     119           0 :         spdk_json_write_named_bool(w, "enabled", spdk_framework_context_switch_monitor_enabled());
     120             : 
     121           0 :         spdk_json_write_object_end(w);
     122           0 :         spdk_jsonrpc_end_result(request, w);
     123             : }
     124             : 
     125           0 : SPDK_RPC_REGISTER("framework_monitor_context_switch", rpc_framework_monitor_context_switch,
     126             :                   SPDK_RPC_RUNTIME)
     127             : 
     128             : struct rpc_get_stats_ctx {
     129             :         struct spdk_jsonrpc_request *request;
     130             :         struct spdk_json_write_ctx *w;
     131             :         uint64_t now;
     132             : };
     133             : 
     134             : static void
     135           0 : rpc_thread_get_stats_done(void *arg)
     136             : {
     137           0 :         struct rpc_get_stats_ctx *ctx = arg;
     138             : 
     139           0 :         spdk_json_write_array_end(ctx->w);
     140           0 :         spdk_json_write_object_end(ctx->w);
     141           0 :         spdk_jsonrpc_end_result(ctx->request, ctx->w);
     142             : 
     143           0 :         free(ctx);
     144           0 : }
     145             : 
     146             : static void
     147           0 : rpc_thread_get_stats_for_each(struct spdk_jsonrpc_request *request, spdk_msg_fn fn)
     148             : {
     149             :         struct rpc_get_stats_ctx *ctx;
     150             : 
     151           0 :         ctx = calloc(1, sizeof(*ctx));
     152           0 :         if (!ctx) {
     153           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
     154             :                                                  "Memory allocation error");
     155           0 :                 return;
     156             :         }
     157           0 :         ctx->request = request;
     158             : 
     159           0 :         ctx->w = spdk_jsonrpc_begin_result(ctx->request);
     160           0 :         spdk_json_write_object_begin(ctx->w);
     161           0 :         spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz());
     162           0 :         spdk_json_write_named_array_begin(ctx->w, "threads");
     163             : 
     164           0 :         spdk_for_each_thread(fn, ctx, rpc_thread_get_stats_done);
     165             : }
     166             : 
     167             : static void
     168           0 : _rpc_thread_get_stats(void *arg)
     169             : {
     170           0 :         struct rpc_get_stats_ctx *ctx = arg;
     171           0 :         struct spdk_thread *thread = spdk_get_thread();
     172           0 :         struct spdk_cpuset tmp_mask = {};
     173             :         struct spdk_poller *poller;
     174             :         struct spdk_thread_stats stats;
     175           0 :         uint64_t active_pollers_count = 0;
     176           0 :         uint64_t timed_pollers_count = 0;
     177           0 :         uint64_t paused_pollers_count = 0;
     178             : 
     179           0 :         for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL;
     180           0 :              poller = spdk_thread_get_next_active_poller(poller)) {
     181           0 :                 active_pollers_count++;
     182             :         }
     183             : 
     184           0 :         for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL;
     185           0 :              poller = spdk_thread_get_next_timed_poller(poller)) {
     186           0 :                 timed_pollers_count++;
     187             :         }
     188             : 
     189           0 :         for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL;
     190           0 :              poller = spdk_thread_get_next_paused_poller(poller)) {
     191           0 :                 paused_pollers_count++;
     192             :         }
     193             : 
     194           0 :         if (0 == spdk_thread_get_stats(&stats)) {
     195           0 :                 spdk_json_write_object_begin(ctx->w);
     196           0 :                 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
     197           0 :                 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
     198           0 :                 spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask());
     199           0 :                 spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread));
     200           0 :                 spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask));
     201           0 :                 spdk_json_write_named_uint64(ctx->w, "busy", stats.busy_tsc);
     202           0 :                 spdk_json_write_named_uint64(ctx->w, "idle", stats.idle_tsc);
     203           0 :                 spdk_json_write_named_uint64(ctx->w, "active_pollers_count", active_pollers_count);
     204           0 :                 spdk_json_write_named_uint64(ctx->w, "timed_pollers_count", timed_pollers_count);
     205           0 :                 spdk_json_write_named_uint64(ctx->w, "paused_pollers_count", paused_pollers_count);
     206           0 :                 spdk_json_write_object_end(ctx->w);
     207             :         }
     208           0 : }
     209             : 
     210             : static void
     211           0 : rpc_thread_get_stats(struct spdk_jsonrpc_request *request,
     212             :                      const struct spdk_json_val *params)
     213             : {
     214           0 :         if (params) {
     215           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     216             :                                                  "'thread_get_stats' requires no arguments");
     217           0 :                 return;
     218             :         }
     219             : 
     220           0 :         rpc_thread_get_stats_for_each(request, _rpc_thread_get_stats);
     221             : }
     222             : 
     223           0 : SPDK_RPC_REGISTER("thread_get_stats", rpc_thread_get_stats, SPDK_RPC_RUNTIME)
     224             : 
     225             : static void
     226           0 : rpc_get_poller(struct spdk_poller *poller, struct spdk_json_write_ctx *w)
     227             : {
     228             :         struct spdk_poller_stats stats;
     229             :         uint64_t period_ticks;
     230             : 
     231           0 :         period_ticks = spdk_poller_get_period_ticks(poller);
     232           0 :         spdk_poller_get_stats(poller, &stats);
     233             : 
     234           0 :         spdk_json_write_object_begin(w);
     235           0 :         spdk_json_write_named_string(w, "name", spdk_poller_get_name(poller));
     236           0 :         spdk_json_write_named_uint64(w, "id", spdk_poller_get_id(poller));
     237           0 :         spdk_json_write_named_string(w, "state", spdk_poller_get_state_str(poller));
     238           0 :         spdk_json_write_named_uint64(w, "run_count", stats.run_count);
     239           0 :         spdk_json_write_named_uint64(w, "busy_count", stats.busy_count);
     240           0 :         if (period_ticks) {
     241           0 :                 spdk_json_write_named_uint64(w, "period_ticks", period_ticks);
     242             :         }
     243           0 :         spdk_json_write_object_end(w);
     244           0 : }
     245             : 
     246             : static void
     247           0 : _rpc_thread_get_pollers(void *arg)
     248             : {
     249           0 :         struct rpc_get_stats_ctx *ctx = arg;
     250           0 :         struct spdk_thread *thread = spdk_get_thread();
     251             :         struct spdk_poller *poller;
     252             : 
     253           0 :         spdk_json_write_object_begin(ctx->w);
     254           0 :         spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
     255           0 :         spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
     256             : 
     257           0 :         spdk_json_write_named_array_begin(ctx->w, "active_pollers");
     258           0 :         for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL;
     259           0 :              poller = spdk_thread_get_next_active_poller(poller)) {
     260           0 :                 rpc_get_poller(poller, ctx->w);
     261             :         }
     262           0 :         spdk_json_write_array_end(ctx->w);
     263             : 
     264           0 :         spdk_json_write_named_array_begin(ctx->w, "timed_pollers");
     265           0 :         for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL;
     266           0 :              poller = spdk_thread_get_next_timed_poller(poller)) {
     267           0 :                 rpc_get_poller(poller, ctx->w);
     268             :         }
     269           0 :         spdk_json_write_array_end(ctx->w);
     270             : 
     271           0 :         spdk_json_write_named_array_begin(ctx->w, "paused_pollers");
     272           0 :         for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL;
     273           0 :              poller = spdk_thread_get_next_paused_poller(poller)) {
     274           0 :                 rpc_get_poller(poller, ctx->w);
     275             :         }
     276           0 :         spdk_json_write_array_end(ctx->w);
     277             : 
     278           0 :         spdk_json_write_object_end(ctx->w);
     279           0 : }
     280             : 
     281             : static void
     282           0 : rpc_thread_get_pollers(struct spdk_jsonrpc_request *request,
     283             :                        const struct spdk_json_val *params)
     284             : {
     285           0 :         if (params) {
     286           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     287             :                                                  "'thread_get_pollers' requires no arguments");
     288           0 :                 return;
     289             :         }
     290             : 
     291           0 :         rpc_thread_get_stats_for_each(request, _rpc_thread_get_pollers);
     292             : }
     293             : 
     294           0 : SPDK_RPC_REGISTER("thread_get_pollers", rpc_thread_get_pollers, SPDK_RPC_RUNTIME)
     295             : 
     296             : static void
     297           0 : rpc_get_io_channel(struct spdk_io_channel *ch, struct spdk_json_write_ctx *w)
     298             : {
     299           0 :         spdk_json_write_object_begin(w);
     300           0 :         spdk_json_write_named_string(w, "name", spdk_io_channel_get_io_device_name(ch));
     301           0 :         spdk_json_write_named_uint32(w, "ref", spdk_io_channel_get_ref_count(ch));
     302           0 :         spdk_json_write_object_end(w);
     303           0 : }
     304             : 
     305             : static void
     306           0 : _rpc_thread_get_io_channels(void *arg)
     307             : {
     308           0 :         struct rpc_get_stats_ctx *ctx = arg;
     309           0 :         struct spdk_thread *thread = spdk_get_thread();
     310             :         struct spdk_io_channel *ch;
     311             : 
     312           0 :         spdk_json_write_object_begin(ctx->w);
     313           0 :         spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
     314             : 
     315           0 :         spdk_json_write_named_array_begin(ctx->w, "io_channels");
     316           0 :         for (ch = spdk_thread_get_first_io_channel(thread); ch != NULL;
     317           0 :              ch = spdk_thread_get_next_io_channel(ch)) {
     318           0 :                 rpc_get_io_channel(ch, ctx->w);
     319             :         }
     320           0 :         spdk_json_write_array_end(ctx->w);
     321             : 
     322           0 :         spdk_json_write_object_end(ctx->w);
     323           0 : }
     324             : 
     325             : static void
     326           0 : rpc_thread_get_io_channels(struct spdk_jsonrpc_request *request,
     327             :                            const struct spdk_json_val *params)
     328             : {
     329           0 :         if (params) {
     330           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     331             :                                                  "'thread_get_io_channels' requires no arguments");
     332           0 :                 return;
     333             :         }
     334             : 
     335           0 :         rpc_thread_get_stats_for_each(request, _rpc_thread_get_io_channels);
     336             : }
     337             : 
     338           0 : SPDK_RPC_REGISTER("thread_get_io_channels", rpc_thread_get_io_channels, SPDK_RPC_RUNTIME);
     339             : 
     340             : static void
     341           0 : rpc_framework_get_reactors_done(void *arg1, void *arg2)
     342             : {
     343           0 :         struct rpc_get_stats_ctx *ctx = arg1;
     344             : 
     345           0 :         spdk_json_write_array_end(ctx->w);
     346           0 :         spdk_json_write_object_end(ctx->w);
     347           0 :         spdk_jsonrpc_end_result(ctx->request, ctx->w);
     348             : 
     349           0 :         free(ctx);
     350           0 : }
     351             : 
     352             : #define GET_DELTA(end, start)   (end >= start ? end - start : 0)
     353             : 
     354             : static void
     355           0 : _rpc_framework_get_reactors(void *arg1, void *arg2)
     356             : {
     357           0 :         struct rpc_get_stats_ctx *ctx = arg1;
     358             :         uint32_t current_core;
     359             :         uint32_t curr_core_freq;
     360             :         uint64_t sys, usr, irq;
     361             :         struct spdk_reactor *reactor;
     362             :         struct spdk_lw_thread *lw_thread;
     363             :         struct spdk_thread *thread;
     364           0 :         struct spdk_cpuset tmp_mask = {};
     365             :         struct spdk_governor *governor;
     366             : 
     367           0 :         current_core = spdk_env_get_current_core();
     368           0 :         reactor = spdk_reactor_get(current_core);
     369             : 
     370           0 :         assert(reactor != NULL);
     371             : 
     372           0 :         spdk_json_write_object_begin(ctx->w);
     373           0 :         spdk_json_write_named_uint32(ctx->w, "lcore", current_core);
     374           0 :         spdk_json_write_named_uint64(ctx->w, "tid", spdk_get_tid());
     375           0 :         spdk_json_write_named_uint64(ctx->w, "busy", reactor->busy_tsc);
     376           0 :         spdk_json_write_named_uint64(ctx->w, "idle", reactor->idle_tsc);
     377           0 :         spdk_json_write_named_bool(ctx->w, "in_interrupt", reactor->in_interrupt);
     378             : 
     379           0 :         if (app_get_proc_stat(current_core, &usr, &sys, &irq) != 0) {
     380           0 :                 irq = sys = usr = 0;
     381             :         }
     382           0 :         spdk_json_write_named_uint64(ctx->w, "irq", irq);
     383           0 :         spdk_json_write_named_uint64(ctx->w, "sys", sys);
     384           0 :         spdk_json_write_named_uint64(ctx->w, "usr", usr);
     385             : 
     386           0 :         governor = spdk_governor_get();
     387           0 :         if (governor != NULL) {
     388             :                 /* Governor returns core freqs in kHz, we want MHz. */
     389           0 :                 curr_core_freq = governor->get_core_curr_freq(current_core) / 1000;
     390           0 :                 spdk_json_write_named_uint32(ctx->w, "core_freq", curr_core_freq);
     391             :         }
     392             : 
     393           0 :         spdk_json_write_named_array_begin(ctx->w, "lw_threads");
     394           0 :         TAILQ_FOREACH(lw_thread, &reactor->threads, link) {
     395           0 :                 thread = spdk_thread_get_from_ctx(lw_thread);
     396             : 
     397           0 :                 spdk_json_write_object_begin(ctx->w);
     398           0 :                 spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
     399           0 :                 spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
     400           0 :                 spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask());
     401           0 :                 spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread));
     402           0 :                 spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask));
     403           0 :                 spdk_json_write_named_uint64(ctx->w, "elapsed",
     404           0 :                                              GET_DELTA(ctx->now, lw_thread->tsc_start));
     405           0 :                 spdk_json_write_object_end(ctx->w);
     406             :         }
     407           0 :         spdk_json_write_array_end(ctx->w);
     408             : 
     409           0 :         spdk_json_write_object_end(ctx->w);
     410           0 : }
     411             : 
     412             : static void
     413           0 : rpc_framework_get_reactors(struct spdk_jsonrpc_request *request,
     414             :                            const struct spdk_json_val *params)
     415             : {
     416             :         struct rpc_get_stats_ctx *ctx;
     417             : 
     418           0 :         if (params) {
     419           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     420             :                                                  "`framework_get_reactors` requires no arguments");
     421           0 :                 return;
     422             :         }
     423             : 
     424           0 :         ctx = calloc(1, sizeof(*ctx));
     425           0 :         if (!ctx) {
     426           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
     427             :                                                  "Memory allocation error");
     428           0 :                 return;
     429             :         }
     430             : 
     431           0 :         ctx->now = spdk_get_ticks();
     432           0 :         ctx->request = request;
     433           0 :         ctx->w = spdk_jsonrpc_begin_result(ctx->request);
     434             : 
     435           0 :         spdk_json_write_object_begin(ctx->w);
     436           0 :         spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz());
     437           0 :         spdk_json_write_named_uint64(ctx->w, "pid", getpid());
     438           0 :         spdk_json_write_named_array_begin(ctx->w, "reactors");
     439             : 
     440           0 :         spdk_for_each_reactor(_rpc_framework_get_reactors, ctx, NULL,
     441             :                               rpc_framework_get_reactors_done);
     442             : }
     443             : 
     444           0 : SPDK_RPC_REGISTER("framework_get_reactors", rpc_framework_get_reactors, SPDK_RPC_RUNTIME)
     445             : 
     446             : struct rpc_set_scheduler_ctx {
     447             :         char *name;
     448             :         uint64_t period;
     449             : };
     450             : 
     451             : static void
     452           0 : free_rpc_framework_set_scheduler(struct rpc_set_scheduler_ctx *r)
     453             : {
     454           0 :         free(r->name);
     455           0 : }
     456             : 
     457             : static const struct spdk_json_object_decoder rpc_set_scheduler_decoders[] = {
     458             :         {"name", offsetof(struct rpc_set_scheduler_ctx, name), spdk_json_decode_string},
     459             :         {"period", offsetof(struct rpc_set_scheduler_ctx, period), spdk_json_decode_uint64, true},
     460             : };
     461             : 
     462             : static void
     463           0 : rpc_framework_set_scheduler(struct spdk_jsonrpc_request *request,
     464             :                             const struct spdk_json_val *params)
     465             : {
     466           0 :         struct rpc_set_scheduler_ctx req = {NULL};
     467             :         struct spdk_scheduler *scheduler;
     468           0 :         bool has_custom_opts = false;
     469             :         int ret;
     470             : 
     471           0 :         ret = spdk_json_decode_object(params, rpc_set_scheduler_decoders,
     472             :                                       SPDK_COUNTOF(rpc_set_scheduler_decoders),
     473             :                                       &req);
     474           0 :         if (ret) {
     475           0 :                 has_custom_opts = true;
     476           0 :                 ret = spdk_json_decode_object_relaxed(params, rpc_set_scheduler_decoders,
     477             :                                                       SPDK_COUNTOF(rpc_set_scheduler_decoders),
     478             :                                                       &req);
     479             :         }
     480           0 :         if (ret) {
     481           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     482             :                                                  "Invalid parameters");
     483           0 :                 goto end;
     484             :         }
     485             : 
     486           0 :         if (req.period != 0) {
     487           0 :                 spdk_scheduler_set_period(req.period);
     488           0 :         } else if (spdk_scheduler_get_period() == 0) {
     489             :                 /* User didn't specify a period, and no period has been set
     490             :                  * previously, so set it now to 1 second.
     491             :                  */
     492           0 :                 spdk_scheduler_set_period(SPDK_SEC_TO_USEC);
     493             :         }
     494             : 
     495           0 :         ret = spdk_scheduler_set(req.name);
     496           0 :         if (ret) {
     497           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
     498             :                                                  spdk_strerror(ret));
     499           0 :                 goto end;
     500             :         }
     501             : 
     502           0 :         scheduler = spdk_scheduler_get();
     503           0 :         if (scheduler != NULL && scheduler->set_opts != NULL) {
     504           0 :                 ret = scheduler->set_opts(params);
     505           0 :         } else if (has_custom_opts) {
     506             :                 /* No custom options are allowed if set_opts are not implemented. */
     507           0 :                 ret = -EINVAL;
     508             :         }
     509           0 :         if (ret) {
     510           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(ret));
     511           0 :                 goto end;
     512             :         }
     513             : 
     514           0 :         spdk_jsonrpc_send_bool_response(request, true);
     515             : 
     516           0 : end:
     517           0 :         free_rpc_framework_set_scheduler(&req);
     518           0 : }
     519           0 : SPDK_RPC_REGISTER("framework_set_scheduler", rpc_framework_set_scheduler,
     520             :                   SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
     521             : 
     522             : static void
     523           0 : rpc_framework_get_scheduler(struct spdk_jsonrpc_request *request,
     524             :                             const struct spdk_json_val *params)
     525             : {
     526             :         struct spdk_json_write_ctx *w;
     527           0 :         struct spdk_scheduler *scheduler = spdk_scheduler_get();
     528           0 :         uint64_t scheduler_period = spdk_scheduler_get_period();
     529           0 :         struct spdk_governor *governor = spdk_governor_get();
     530           0 :         uint32_t scheduling_core = spdk_scheduler_get_scheduling_lcore();
     531             : 
     532           0 :         if (params) {
     533           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     534             :                                                  "'rpc_get_scheduler' requires no arguments");
     535           0 :                 return;
     536             :         }
     537             : 
     538           0 :         w = spdk_jsonrpc_begin_result(request);
     539           0 :         spdk_json_write_object_begin(w);
     540           0 :         if (scheduler) {
     541           0 :                 spdk_json_write_named_string(w, "scheduler_name", scheduler->name);
     542             :         }
     543           0 :         spdk_json_write_named_uint64(w, "scheduler_period", scheduler_period);
     544           0 :         spdk_json_write_named_string(w, "isolated_core_mask", scheduler_get_isolated_core_mask());
     545           0 :         spdk_json_write_named_uint32(w, "scheduling_core", scheduling_core);
     546           0 :         if (governor != NULL) {
     547           0 :                 spdk_json_write_named_string(w, "governor_name", governor->name);
     548             :         }
     549             : 
     550           0 :         if (scheduler != NULL && scheduler->get_opts != NULL) {
     551           0 :                 scheduler->get_opts(w);
     552             :         }
     553             : 
     554           0 :         spdk_json_write_object_end(w);
     555           0 :         spdk_jsonrpc_end_result(request, w);
     556             : }
     557           0 : SPDK_RPC_REGISTER("framework_get_scheduler", rpc_framework_get_scheduler,
     558             :                   SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
     559             : 
     560             : static void
     561           0 : rpc_framework_get_governor(struct spdk_jsonrpc_request *request,
     562             :                            const struct spdk_json_val *params)
     563             : {
     564             :         struct spdk_json_write_ctx *w;
     565           0 :         struct spdk_governor *governor = spdk_governor_get();
     566             : 
     567           0 :         if (params) {
     568           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     569             :                                                  "'rpc_get_governor' requires no arguments");
     570           0 :                 return;
     571             :         }
     572             : 
     573           0 :         w = spdk_jsonrpc_begin_result(request);
     574           0 :         spdk_json_write_object_begin(w);
     575             : 
     576           0 :         if (governor != NULL) {
     577             :                 uint32_t core, index, num;
     578             :                 uint32_t freqs[SPDK_MAX_LCORE_FREQS];
     579             : 
     580           0 :                 spdk_json_write_named_string(w, "governor_name", governor->name);
     581             : 
     582           0 :                 spdk_json_write_named_object_begin(w, "module_specific");
     583             : 
     584           0 :                 governor->dump_info_json(w);
     585             : 
     586           0 :                 spdk_json_write_object_end(w);
     587             : 
     588           0 :                 spdk_json_write_named_array_begin(w, "cores");
     589             : 
     590           0 :                 SPDK_ENV_FOREACH_CORE(core) {
     591           0 :                         spdk_json_write_object_begin(w);
     592           0 :                         spdk_json_write_named_uint32(w, "lcore_id", core);
     593             : 
     594           0 :                         memset(freqs, 0, SPDK_MAX_LCORE_FREQS * sizeof(uint32_t));
     595             : 
     596           0 :                         num = governor->get_core_avail_freqs(core, freqs, SPDK_MAX_LCORE_FREQS);
     597             : 
     598           0 :                         spdk_json_write_named_array_begin(w, "available_frequencies");
     599           0 :                         for (index = 0; index < num; index++) {
     600           0 :                                 spdk_json_write_uint32(w, freqs[index]);
     601             :                         }
     602           0 :                         spdk_json_write_array_end(w);
     603             : 
     604           0 :                         spdk_json_write_named_uint32(w, "current_frequency", governor->get_core_curr_freq(core));
     605           0 :                         spdk_json_write_object_end(w);
     606             :                 }
     607             : 
     608           0 :                 spdk_json_write_array_end(w);
     609             :         }
     610             : 
     611           0 :         spdk_json_write_object_end(w);
     612           0 :         spdk_jsonrpc_end_result(request, w);
     613             : }
     614           0 : SPDK_RPC_REGISTER("framework_get_governor", rpc_framework_get_governor, SPDK_RPC_RUNTIME)
     615             : 
     616             : struct rpc_set_scheduler_opts_ctx {
     617             :         char *isolated_core_mask;
     618             :         uint32_t scheduling_core;
     619             : };
     620             : 
     621             : static const struct spdk_json_object_decoder rpc_set_scheduler_opts_decoders[] = {
     622             :         {"isolated_core_mask", offsetof(struct rpc_set_scheduler_opts_ctx, isolated_core_mask), spdk_json_decode_string, true},
     623             :         {"scheduling_core", offsetof(struct rpc_set_scheduler_opts_ctx, scheduling_core), spdk_json_decode_uint32, true},
     624             : };
     625             : 
     626             : static void
     627           0 : free_rpc_scheduler_set_options(struct rpc_set_scheduler_opts_ctx *r)
     628             : {
     629           0 :         free(r->isolated_core_mask);
     630           0 : }
     631             : 
     632             : static void
     633           0 : rpc_scheduler_set_options(struct spdk_jsonrpc_request *request,
     634             :                           const struct spdk_json_val *params)
     635             : {
     636           0 :         struct rpc_set_scheduler_opts_ctx req = {NULL};
     637             :         struct spdk_cpuset core_mask;
     638             : 
     639           0 :         req.scheduling_core = spdk_scheduler_get_scheduling_lcore();
     640             : 
     641           0 :         if (spdk_json_decode_object(params, rpc_set_scheduler_opts_decoders,
     642             :                                     SPDK_COUNTOF(rpc_set_scheduler_opts_decoders), &req)) {
     643           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     644             :                                                  "Invalid parameters");
     645           0 :                 goto end;
     646             :         }
     647             : 
     648           0 :         if (req.isolated_core_mask != NULL) {
     649           0 :                 spdk_cpuset_parse(&core_mask, req.isolated_core_mask);
     650           0 :                 if (spdk_cpuset_get_cpu(&core_mask, req.scheduling_core)) {
     651           0 :                         spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     652             :                                                          "Scheduling core cannot be included in isolated core mask.\n");
     653           0 :                         goto end;
     654             :                 }
     655           0 :                 if (scheduler_set_isolated_core_mask(core_mask) == false) {
     656           0 :                         spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     657             :                                                          "Invalid isolated core mask\n");
     658           0 :                         goto end;
     659             :                 }
     660             :         }
     661             : 
     662           0 :         if (spdk_scheduler_set_scheduling_lcore(req.scheduling_core) == false) {
     663           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     664             :                                                  "Invalid scheduling core.\n");
     665           0 :                 goto end;
     666             :         }
     667             : 
     668           0 :         spdk_jsonrpc_send_bool_response(request, true);
     669           0 : end:
     670           0 :         free_rpc_scheduler_set_options(&req);
     671           0 : }
     672           0 : SPDK_RPC_REGISTER("scheduler_set_options", rpc_scheduler_set_options, SPDK_RPC_STARTUP)
     673             : 
     674             : struct rpc_thread_set_cpumask_ctx {
     675             :         struct spdk_jsonrpc_request *request;
     676             :         struct spdk_cpuset cpumask;
     677             :         int status;
     678             :         struct spdk_thread *orig_thread;
     679             : };
     680             : 
     681             : static void
     682           0 : rpc_thread_set_cpumask_done(void *_ctx)
     683             : {
     684           0 :         struct rpc_thread_set_cpumask_ctx *ctx = _ctx;
     685             : 
     686           0 :         if (ctx->status == 0) {
     687           0 :                 spdk_jsonrpc_send_bool_response(ctx->request, true);
     688             :         } else {
     689           0 :                 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
     690           0 :                                                  spdk_strerror(-ctx->status));
     691             :         }
     692             : 
     693           0 :         free(ctx);
     694           0 : }
     695             : 
     696             : static void
     697           0 : _rpc_thread_set_cpumask(void *_ctx)
     698             : {
     699           0 :         struct rpc_thread_set_cpumask_ctx *ctx = _ctx;
     700             : 
     701           0 :         ctx->status = spdk_thread_set_cpumask(&ctx->cpumask);
     702             : 
     703           0 :         spdk_thread_send_msg(ctx->orig_thread, rpc_thread_set_cpumask_done, ctx);
     704           0 : }
     705             : 
     706             : struct rpc_thread_set_cpumask {
     707             :         uint64_t id;
     708             :         char *cpumask;
     709             : };
     710             : 
     711             : static const struct spdk_json_object_decoder rpc_thread_set_cpumask_decoders[] = {
     712             :         {"id", offsetof(struct rpc_thread_set_cpumask, id), spdk_json_decode_uint64},
     713             :         {"cpumask", offsetof(struct rpc_thread_set_cpumask, cpumask), spdk_json_decode_string},
     714             : };
     715             : 
     716             : static void
     717           0 : rpc_thread_set_cpumask(struct spdk_jsonrpc_request *request,
     718             :                        const struct spdk_json_val *params)
     719             : {
     720           0 :         struct rpc_thread_set_cpumask req = {};
     721             :         struct rpc_thread_set_cpumask_ctx *ctx;
     722             :         const struct spdk_cpuset *coremask;
     723             :         struct spdk_cpuset tmp_mask;
     724             :         struct spdk_thread *thread;
     725             :         int rc;
     726             : 
     727           0 :         ctx = calloc(1, sizeof(*ctx));
     728           0 :         if (ctx == NULL) {
     729           0 :                 SPDK_ERRLOG("Memory allocation failed\n");
     730           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
     731             :                                                  "Memory allocation failed");
     732           0 :                 return;
     733             :         }
     734             : 
     735           0 :         if (spdk_json_decode_object(params, rpc_thread_set_cpumask_decoders,
     736             :                                     SPDK_COUNTOF(rpc_thread_set_cpumask_decoders),
     737             :                                     &req)) {
     738           0 :                 SPDK_ERRLOG("spdk_json_decode_object failed\n");
     739           0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     740             :                                                  "spdk_json_decode_object failed");
     741           0 :                 goto err;
     742             :         }
     743             : 
     744           0 :         thread = spdk_thread_get_by_id(req.id);
     745           0 :         if (thread == NULL) {
     746           0 :                 SPDK_ERRLOG("Thread %" PRIu64 " does not exist\n", req.id);
     747           0 :                 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     748             :                                                      "Thread %" PRIu64 " does not exist", req.id);
     749           0 :                 goto err;
     750             :         }
     751             : 
     752           0 :         rc = spdk_app_parse_core_mask(req.cpumask, &ctx->cpumask);
     753           0 :         if (rc != 0) {
     754           0 :                 SPDK_ERRLOG("Invalid cpumask %s\n", req.cpumask);
     755           0 :                 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
     756             :                                                      "Invalid cpumask %s", req.cpumask);
     757           0 :                 goto err;
     758             :         }
     759             : 
     760           0 :         if (spdk_cpuset_count(&ctx->cpumask) == 0) {
     761           0 :                 coremask = spdk_app_get_core_mask();
     762           0 :                 spdk_cpuset_copy(&tmp_mask, coremask);
     763           0 :                 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
     764             :                                                      "No CPU is selected from reactor mask %s",
     765             :                                                      spdk_cpuset_fmt(&tmp_mask));
     766           0 :                 goto err;
     767             :         }
     768             : 
     769             :         /* There may be any reactors running in interrupt mode. But currently,
     770             :          * when interrupt ability of the spdk_thread is not enabled,
     771             :          * spdk_thread can't get executed on reactor which runs in interrupt.
     772             :          * Exclude the situation that reactors specified by the cpumask are
     773             :          * all in interrupt mode.
     774             :          */
     775           0 :         if (!spdk_interrupt_mode_is_enabled()) {
     776           0 :                 struct spdk_reactor *local_reactor = spdk_reactor_get(spdk_env_get_current_core());
     777             :                 struct spdk_cpuset tmp_cpuset;
     778             : 
     779             :                 /* Masking off reactors which are in interrupt mode */
     780           0 :                 spdk_cpuset_copy(&tmp_cpuset, &local_reactor->notify_cpuset);
     781           0 :                 spdk_cpuset_negate(&tmp_cpuset);
     782           0 :                 spdk_cpuset_and(&tmp_cpuset, &ctx->cpumask);
     783           0 :                 if (spdk_cpuset_count(&tmp_cpuset) == 0) {
     784           0 :                         spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
     785             :                                                              "cpumask %s are all in interrupt mode, and can't be scheduled yet",
     786             :                                                              req.cpumask);
     787           0 :                         goto err;
     788             :                 }
     789             :         }
     790             : 
     791           0 :         ctx->request = request;
     792           0 :         ctx->orig_thread = spdk_get_thread();
     793             : 
     794           0 :         spdk_thread_send_msg(thread, _rpc_thread_set_cpumask, ctx);
     795             : 
     796           0 :         free(req.cpumask);
     797           0 :         return;
     798             : 
     799           0 : err:
     800           0 :         free(req.cpumask);
     801           0 :         free(ctx);
     802             : }
     803           0 : SPDK_RPC_REGISTER("thread_set_cpumask", rpc_thread_set_cpumask, SPDK_RPC_RUNTIME)
     804           0 : SPDK_LOG_REGISTER_COMPONENT(app_rpc)

Generated by: LCOV version 1.15