| /*****************************************************************************\ |
| * job_info.c - Functions related to job display mode of sview. |
| ***************************************************************************** |
| * Copyright (C) SchedMD LLC. |
| * Copyright (C) 2008-2011 Lawrence Livermore National Security. |
| * Copyright (C) 2004-2007 The Regents of the University of California. |
| * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). |
| * Written by Danny Auble <da@llnl.gov> |
| * |
| * CODE-OCEC-09-009. All rights reserved. |
| * |
| * This file is part of Slurm, a resource management program. |
| * For details, see <https://slurm.schedmd.com/>. |
| * Please also read the included file: DISCLAIMER. |
| * |
| * Slurm is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with Slurm; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #include <fcntl.h> |
| #include <grp.h> |
| #include <limits.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #include "src/common/parse_time.h" |
| #include "src/common/proc_args.h" |
| #include "src/interfaces/select.h" |
| #include "src/common/uid.h" |
| #include "src/common/xstring.h" |
| |
| #include "src/sview/sview.h" |
| |
| #define _DEBUG 0 |
| #define MAX_CANCEL_RETRY 10 |
| #define SIZE(a) (sizeof(a)/sizeof(a[0])) |
| |
| /* We do not read the node table here, but allocated space for up to |
| * MAX_NODE_SPACE nodes and generate fatal error if we go higher. Increase |
| * this value if needed */ |
| #ifndef SVIEW_MAX_NODE_SPACE |
| #define SVIEW_MAX_NODE_SPACE (24 * 1024) |
| #endif |
| |
| /* Collection of data for printing reports. Like data is combined here */ |
| typedef struct { |
| int color_inx; |
| GtkTreeIter iter_ptr; |
| bool iter_set; |
| uint32_t job_id; |
| char *job_id_str; |
| job_info_t *job_ptr; |
| int node_cnt; |
| char *nodes; |
| int pos; |
| list_t *step_list; |
| hostlist_t *task_hl; |
| char *task_hl_str; |
| hostlist_t *task_pending_hl; |
| char *task_pending_hl_str; |
| list_t *task_list; |
| list_t *task_pending_list; |
| } sview_job_info_t; |
| |
| static list_t *foreach_list = NULL; |
| static char *stacked_job_list = NULL; |
| |
| typedef struct { |
| int state; |
| slurm_step_id_t step_id; |
| int array_job_id; |
| int array_task_id; |
| int het_job_id; |
| int het_job_offset; |
| } jobs_foreach_t; |
| |
| typedef struct { |
| int edit_type; |
| GtkWidget *entry; |
| job_desc_msg_t *job_msg; |
| char *type; |
| } jobs_foreach_common_t; |
| |
| enum { |
| EDIT_SIGNAL = 1, |
| EDIT_SIGNAL_USER, |
| EDIT_CANCEL, |
| EDIT_CANCEL_USER, |
| EDIT_REQUEUE, |
| EDIT_SUSPEND, |
| EDIT_EDIT |
| }; |
| |
| /* These need to be in alpha order (except POS and CNT) */ |
| enum { |
| SORTID_POS = POS_LOC, |
| SORTID_ACCOUNT, |
| SORTID_ACTION, |
| SORTID_ALLOC, |
| SORTID_ALLOC_NODE, |
| SORTID_ARRAY_JOB_ID, |
| SORTID_ARRAY_TASK_ID, |
| SORTID_BATCH, |
| SORTID_BATCH_HOST, |
| SORTID_BURST_BUFFER, |
| SORTID_CLUSTER_NAME, |
| SORTID_COLOR, |
| SORTID_COLOR_INX, |
| SORTID_COMMAND, |
| SORTID_COMMENT, |
| SORTID_CONTIGUOUS, |
| SORTID_CORE_SPEC, |
| /* SORTID_CORES_MAX, */ |
| /* SORTID_CORES_MIN, */ |
| SORTID_CPUS, |
| SORTID_CPUS_PER_TRES, |
| SORTID_CPU_MAX, |
| SORTID_CPU_MIN, |
| SORTID_CPUS_PER_TASK, |
| SORTID_DEADLINE, |
| SORTID_DEPENDENCY, |
| SORTID_DERIVED_EC, |
| SORTID_EXIT_CODE, |
| SORTID_EXTRA, |
| SORTID_FEATURES, |
| SORTID_FED_ACTIVE_SIBS, |
| SORTID_FED_ORIGIN, |
| SORTID_FED_VIABLE_SIBS, |
| SORTID_GRES, |
| SORTID_GROUP_ID, |
| SORTID_HET_JOB_ID, |
| SORTID_HET_JOB_ID_SET, |
| SORTID_HET_JOB_OFFSET, |
| SORTID_JOBID, |
| SORTID_JOBID_FORMATTED, |
| SORTID_LAST_SCHED_EVAL, |
| SORTID_LICENSES, |
| SORTID_MCS_LABEL, |
| SORTID_CPU_REQ, |
| SORTID_MEM_MIN, |
| SORTID_MEM_PER_TRES, |
| SORTID_TMP_DISK, |
| SORTID_NAME, |
| SORTID_NETWORK, |
| SORTID_NICE, |
| SORTID_NODELIST, |
| SORTID_NODELIST_EXC, |
| SORTID_NODELIST_REQ, |
| SORTID_NODELIST_SCHED, |
| SORTID_NODE_INX, |
| SORTID_NODES, |
| SORTID_NODES_MAX, |
| SORTID_NODES_MIN, |
| /* SORTID_NTASKS_PER_CORE, */ |
| /* SORTID_NTASKS_PER_NODE, */ |
| /* SORTID_NTASKS_PER_SOCKET, */ |
| SORTID_OVER_SUBSCRIBE, |
| SORTID_PARTITION, |
| SORTID_PREEMPT_TIME, |
| SORTID_PREFER, |
| SORTID_PRIORITY, |
| SORTID_QOS, |
| SORTID_REASON, |
| SORTID_REBOOT, |
| SORTID_REQUEUE, |
| SORTID_RESV_NAME, |
| SORTID_RESTARTS, |
| /* SORTID_SOCKETS_MAX, */ |
| /* SORTID_SOCKETS_MIN, */ |
| SORTID_STATE, |
| SORTID_STATE_NUM, |
| SORTID_STD_ERR, |
| SORTID_STD_IN, |
| SORTID_STD_OUT, |
| SORTID_SWITCHES, |
| SORTID_TASKS, |
| SORTID_THREAD_SPEC, |
| /* SORTID_THREADS_MAX, */ |
| /* SORTID_THREADS_MIN, */ |
| SORTID_TIME_ACCRUE, |
| SORTID_TIME_ELIGIBLE, |
| SORTID_TIME_END, |
| SORTID_TIMELIMIT, |
| SORTID_TIME_RESIZE, |
| SORTID_TIME_RUNNING, |
| SORTID_TIME_START, |
| SORTID_TIME_SUBMIT, |
| SORTID_TIME_SUSPEND, |
| SORTID_TRES_ALLOC, |
| SORTID_TRES_BIND, |
| SORTID_TRES_FREQ, |
| SORTID_TRES_PER_JOB, |
| SORTID_TRES_PER_NODE, |
| SORTID_TRES_PER_SOCKET, |
| SORTID_TRES_PER_TASK, |
| SORTID_UPDATED, |
| SORTID_USER_ID, |
| SORTID_WCKEY, |
| SORTID_WORKDIR, |
| SORTID_CNT |
| }; |
| |
| /* extra field here is for choosing the type of edit that will |
| * take place. If you choose EDIT_MODEL (means only display a set of |
| * known options) create it in function create_model_*. |
| */ |
| static char *_initial_page_opts = ("JobID,Partition,UserID,Name," |
| "State,Time_Running,Node_Count,NodeList"); |
| |
| static display_data_t display_data_job[] = { |
| {G_TYPE_INT, SORTID_POS, NULL, false, EDIT_NONE, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_JOBID, "JobID", false, EDIT_NONE, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_JOBID_FORMATTED, NULL, false, EDIT_NONE, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_COLOR, NULL, true, EDIT_COLOR, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_ACTION, "Action", false, |
| EDIT_MODEL, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_INT, SORTID_ALLOC, NULL, false, EDIT_NONE, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_ARRAY_JOB_ID, "Array_Job_ID", false, EDIT_NONE, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_ARRAY_TASK_ID, "Array_Task_ID", false, EDIT_NONE, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_PARTITION, "Partition", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_HET_JOB_ID, "Hetjob JobID", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_HET_JOB_ID_SET, "Hetjob JobID Set", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_HET_JOB_OFFSET, "Hetjob Offset", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_USER_ID, "UserID", false, EDIT_NONE, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_GROUP_ID, "GroupID", false, EDIT_NONE, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_WCKEY, "WCKey", false, EDIT_TEXTBOX, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NAME, "Name", false, EDIT_TEXTBOX, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_STATE, "State", false, EDIT_NONE, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_INT, SORTID_STATE_NUM, NULL, false, EDIT_NONE, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_PREEMPT_TIME, "Preempt Time", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIME_RESIZE, "Time Resize", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIME_RUNNING, "Time Running", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIME_SUBMIT, "Time Submit", false, |
| EDIT_NONE, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIME_ACCRUE, "Time Accrue", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIME_ELIGIBLE, "Time Eligible", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIME_START, "Time Start", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIME_END, "Time End", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_DEADLINE, "Deadline", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIME_SUSPEND, "Time Suspended", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TIMELIMIT, "Time Limit", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NODES, "Node Count", false, EDIT_TEXTBOX, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CPUS, "CPU Count", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NODELIST, "NodeList", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NODELIST_EXC, "NodeList Excluded", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NODELIST_REQ, "NodeList Requested", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NODELIST_SCHED, "NodeList Scheduled", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CONTIGUOUS, "Contiguous", false, EDIT_MODEL, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CORE_SPEC, "CoreSpec", false, EDIT_TEXTBOX, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_THREAD_SPEC, "ThreadSpec", false, EDIT_TEXTBOX, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_REBOOT, "Reboot", false, EDIT_MODEL, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_REQUEUE, "Requeue", false, EDIT_MODEL, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_INT, SORTID_RESTARTS, "Restart Count", false, EDIT_NONE, |
| refresh_job, create_model_job, admin_edit_job}, |
| /* Priority is a string so we can edit using a text box */ |
| {G_TYPE_STRING, SORTID_PRIORITY, "Priority", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_DERIVED_EC, "Derived Exit Code", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_EXIT_CODE, "Exit Code", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_BATCH, "Batch Flag", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_BATCH_HOST, "Batch Host", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_BURST_BUFFER, "Burst Buffer", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CLUSTER_NAME, "ClusterName", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CPU_MIN, "CPUs Min", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CPU_MAX, "CPUs Max", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TASKS, "Task Count", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_OVER_SUBSCRIBE, "OverSubscribe", false, |
| EDIT_MODEL, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_STD_ERR, "Standard Error", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_STD_IN, "Standard In", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_STD_OUT, "Standard Out", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CPUS_PER_TASK, "CPUs per Task", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_RESV_NAME, "Reservation Name", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NODES_MIN, "Nodes (minimum)", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NODES_MAX, "Nodes Max", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CPU_REQ, "Min CPUs Per Node", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_MEM_MIN, "Min Memory", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TMP_DISK, "Min Tmp Disk Per Node", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| /* Nice is a string so we can edit using a text box */ |
| {G_TYPE_STRING, SORTID_NICE, "Nice", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_ACCOUNT, "Account", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_QOS, "QOS", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_REASON, "Reason Waiting", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_SWITCHES, "Switches", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_FEATURES, "Features", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_PREFER, "Prefer", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_FED_ACTIVE_SIBS, "FedActiveSiblings", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_FED_ORIGIN, "FedOrigin", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_FED_VIABLE_SIBS, "FedViableSiblings", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| /* "gres" replaced by "tres_per_node" in v18.08 */ |
| {G_TYPE_STRING, SORTID_GRES, "Gres", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_LAST_SCHED_EVAL, "Last Sched Eval", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_LICENSES, "Licenses", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_MCS_LABEL, "MCS_Label", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_DEPENDENCY, "Dependency", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_ALLOC_NODE, "Alloc Node : Sid", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_NETWORK, "Network", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_COMMAND, "Command", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_COMMENT, "Comment", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_EXTRA, "Extra", |
| false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_WORKDIR, "Work Dir", |
| false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_INT, SORTID_COLOR_INX, NULL, false, EDIT_NONE, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_POINTER, SORTID_NODE_INX, NULL, false, EDIT_NONE, |
| refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_CPUS_PER_TRES, "CPUs per TRES", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_MEM_PER_TRES, "Mem per TRES", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TRES_ALLOC, "TRES Alloc", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TRES_BIND, "TRES Bind", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TRES_FREQ, "TRES Freq", false, |
| EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TRES_PER_JOB, "TRES Per Job", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TRES_PER_NODE, "TRES Per Node", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TRES_PER_SOCKET, "TRES Per Socket", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_STRING, SORTID_TRES_PER_TASK, "TRES Per Task", false, |
| EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, |
| {G_TYPE_INT, SORTID_UPDATED, NULL, false, EDIT_NONE, refresh_job, |
| create_model_job, admin_edit_job}, |
| {G_TYPE_NONE, -1, NULL, false, EDIT_NONE} |
| }; |
| |
| static display_data_t options_data_job[] = { |
| {G_TYPE_INT, SORTID_POS, NULL, false, EDIT_NONE}, |
| {G_TYPE_STRING, INFO_PAGE, "Full Info", true, JOB_PAGE}, |
| {G_TYPE_STRING, JOB_PAGE, "Signal", true, ADMIN_PAGE}, |
| {G_TYPE_STRING, JOB_PAGE, "Requeue", true, ADMIN_PAGE}, |
| {G_TYPE_STRING, JOB_PAGE, "Cancel", true, ADMIN_PAGE}, |
| {G_TYPE_STRING, JOB_PAGE, "Suspend/Resume", true, ADMIN_PAGE}, |
| {G_TYPE_STRING, JOB_PAGE, "Edit Job", true, ADMIN_PAGE}, |
| {G_TYPE_STRING, PART_PAGE, "Partition", true, JOB_PAGE}, |
| {G_TYPE_STRING, NODE_PAGE, "Nodes", true, JOB_PAGE}, |
| {G_TYPE_STRING, RESV_PAGE, "Reservation", true, JOB_PAGE}, |
| {G_TYPE_NONE, -1, NULL, false, EDIT_NONE} |
| }; |
| |
| struct signv { |
| char *name; |
| uint16_t val; |
| } sig_name_num[ ] = { |
| { "HUP", SIGHUP }, |
| { "INT", SIGINT }, |
| { "QUIT", SIGQUIT }, |
| { "ABRT", SIGABRT }, |
| { "KILL", SIGKILL }, |
| { "ALRM", SIGALRM }, |
| { "TERM", SIGTERM }, |
| { "USR1", SIGUSR1 }, |
| { "USR2", SIGUSR2 }, |
| { "CONT", SIGCONT }, |
| { "STOP", SIGSTOP }, |
| { "TSTP", SIGTSTP }, |
| { "TTIN", SIGTTIN }, |
| { "TTOU", SIGTTOU }, |
| { "XCPU", SIGXCPU }, |
| { "SIGHUP", SIGHUP }, |
| { "SIGINT", SIGINT }, |
| { "SIGQUIT", SIGQUIT }, |
| { "SIGABRT", SIGABRT }, |
| { "SIGKILL", SIGKILL }, |
| { "SIGALRM", SIGALRM }, |
| { "SIGTERM", SIGTERM }, |
| { "SIGUSR1", SIGUSR1 }, |
| { "SIGUSR2", SIGUSR2 }, |
| { "SIGCONT", SIGCONT }, |
| { "SIGSTOP", SIGSTOP }, |
| { "SIGTSTP", SIGTSTP }, |
| { "SIGTTIN", SIGTTIN }, |
| { "SIGTTOU", SIGTTOU }, |
| { "SIGXCPU", SIGXCPU }, |
| }; |
| |
| static display_data_t *local_display_data = NULL; |
| static char *got_edit_signal = NULL; |
| static GtkTreeModel *last_model = NULL; |
| |
| static void _update_info_task(sview_job_info_t *sview_job_info_ptr, |
| GtkTreeModel *model, |
| GtkTreeIter *task_iter, |
| GtkTreeIter *iter, bool handle_pending); |
| |
| static void _update_info_step(sview_job_info_t *sview_job_info_ptr, |
| GtkTreeModel *model, |
| GtkTreeIter *step_iter, |
| GtkTreeIter *iter); |
| |
| static char *_read_file(const char *f_name) |
| { |
| int fd, f_size, offset = 0; |
| ssize_t rd_size; |
| struct stat f_stat; |
| char *buf; |
| |
| fd = open(f_name, 0); |
| if (fd < 0) |
| return NULL; |
| if (fstat(fd, &f_stat)) { |
| close(fd); |
| return NULL; |
| } |
| f_size = f_stat.st_size; |
| buf = xmalloc(f_size + 1); |
| while (offset < f_size) { |
| rd_size = read(fd, buf+offset, f_size-offset); |
| if (rd_size < 0) { |
| if ((errno == EAGAIN) || (errno == EINTR)) |
| continue; |
| xfree(buf); |
| break; |
| } |
| offset += rd_size; |
| } |
| close(fd); |
| buf[f_size] = '\0'; |
| return buf; |
| } |
| |
| static void _job_info_free(sview_job_info_t *sview_job_info) |
| { |
| if (sview_job_info) { |
| xfree(sview_job_info->job_id_str); |
| xfree(sview_job_info->nodes); |
| |
| FREE_NULL_LIST(sview_job_info->step_list); |
| FREE_NULL_LIST(sview_job_info->task_list); |
| FREE_NULL_LIST(sview_job_info->task_pending_list); |
| |
| xfree(sview_job_info->task_hl_str); |
| xfree(sview_job_info->task_pending_hl_str); |
| |
| FREE_NULL_HOSTLIST(sview_job_info->task_hl); |
| FREE_NULL_HOSTLIST(sview_job_info->task_pending_hl); |
| } |
| } |
| |
| static void _job_info_list_del(void *object) |
| { |
| sview_job_info_t *sview_job_info = (sview_job_info_t *)object; |
| |
| if (sview_job_info) { |
| _job_info_free(sview_job_info); |
| xfree(sview_job_info); |
| } |
| } |
| |
| /* translate signal name to number */ |
| static uint16_t _xlate_signal_name(const char *signal_name) |
| { |
| uint16_t sig_num = NO_VAL16; |
| char *end_ptr, *sig_names = NULL; |
| int i; |
| |
| sig_num = (uint16_t) strtol(signal_name, &end_ptr, 10); |
| |
| if ((*end_ptr == '\0') && (sig_num != 0)) |
| return sig_num; |
| |
| for (i=0; i<SIZE(sig_name_num); i++) { |
| if (xstrcasecmp(sig_name_num[i].name, signal_name) == 0) { |
| xfree(sig_names); |
| return sig_name_num[i].val; |
| } |
| if (i == 0) |
| sig_names = xstrdup(sig_name_num[i].name); |
| else { |
| xstrcat(sig_names, ","); |
| xstrcat(sig_names, sig_name_num[i].name); |
| } |
| } |
| xfree(sig_names); |
| return NO_VAL16; |
| } |
| |
| static int _cancel_job_id (uint32_t job_id, uint16_t signal) |
| { |
| int error_code = SLURM_SUCCESS, i; |
| char *temp = NULL; |
| |
| if (signal == (uint16_t)-1) |
| signal = SIGKILL; |
| for (i = 0; i < MAX_CANCEL_RETRY; i++) { |
| /* NOTE: RPC always sent to slurmctld rather than directly |
| * to slurmd daemons */ |
| error_code = slurm_kill_job(job_id, signal, false); |
| if (error_code == 0 |
| || (errno != ESLURM_TRANSITION_STATE_NO_UPDATE |
| && errno != ESLURM_JOB_PENDING)) |
| break; |
| temp = g_strdup_printf("Sending signal %u to job %u", |
| signal, job_id); |
| display_edit_note(temp); |
| g_free(temp); |
| sleep ( 5 + i ); |
| } |
| if (error_code) { |
| error_code = errno; |
| if ((error_code != ESLURM_ALREADY_DONE) && |
| (error_code != ESLURM_INVALID_JOB_ID)) { |
| temp = g_strdup_printf( |
| "Kill job error on job id %u: %s", |
| job_id, slurm_strerror(errno)); |
| display_edit_note(temp); |
| g_free(temp); |
| } else { |
| display_edit_note(slurm_strerror(errno)); |
| } |
| } |
| |
| return error_code; |
| } |
| |
| static int _cancel_step_id(uint32_t job_id, uint32_t step_id, |
| uint16_t signal) |
| { |
| int error_code = SLURM_SUCCESS, i; |
| char *temp = NULL; |
| char tmp_char[45]; |
| slurm_step_id_t step_id_tmp = { |
| .job_id = job_id, |
| .step_het_comp = NO_VAL, |
| .step_id = step_id, |
| }; |
| |
| log_build_step_id_str(&step_id_tmp, tmp_char, sizeof(tmp_char), |
| STEP_ID_FLAG_NONE); |
| |
| if (signal == (uint16_t)-1) |
| signal = SIGKILL; |
| |
| for (i = 0; i < MAX_CANCEL_RETRY; i++) { |
| /* NOTE: RPC always sent to slurmctld rather than directly |
| * to slurmd daemons */ |
| error_code = slurm_kill_job_step(job_id, step_id, signal, 0); |
| |
| if (error_code == 0 |
| || (errno != ESLURM_TRANSITION_STATE_NO_UPDATE |
| && errno != ESLURM_JOB_PENDING)) |
| break; |
| temp = g_strdup_printf("Sending signal %u to %s", |
| signal, tmp_char); |
| display_edit_note(temp); |
| g_free(temp); |
| sleep ( 5 + i ); |
| } |
| |
| if (error_code) { |
| error_code = errno; |
| if (error_code != ESLURM_ALREADY_DONE) { |
| temp = g_strdup_printf( |
| "Kill job error on %s: %s", |
| tmp_char, slurm_strerror(errno)); |
| display_edit_note(temp); |
| g_free(temp); |
| } else { |
| display_edit_note(slurm_strerror(errno)); |
| } |
| } |
| |
| return error_code; |
| } |
| |
| static void _set_active_combo_job(GtkComboBox *combo, |
| GtkTreeModel *model, GtkTreeIter *iter, |
| int type) |
| { |
| char *temp_char = NULL; |
| int action = 0; |
| |
| if (model) |
| gtk_tree_model_get(model, iter, type, &temp_char, -1); |
| if (!temp_char) |
| goto end_it; |
| switch(type) { |
| case SORTID_ACTION: |
| if (!xstrcasecmp(temp_char, "None")) |
| action = 0; |
| else if (!xstrcasecmp(temp_char, "Cancel")) |
| action = 1; |
| else if (!xstrcasecmp(temp_char, "Suspend")) |
| action = 2; |
| else if (!xstrcasecmp(temp_char, "Resume")) |
| action = 3; |
| else if (!xstrcasecmp(temp_char, "Requeue")) |
| action = 5; |
| else |
| action = 0; |
| |
| break; |
| case SORTID_CONTIGUOUS: |
| case SORTID_REBOOT: |
| case SORTID_REQUEUE: |
| case SORTID_OVER_SUBSCRIBE: |
| if (!xstrcasecmp(temp_char, "yes")) |
| action = 0; |
| else if (!xstrcasecmp(temp_char, "no")) |
| action = 1; |
| else |
| action = 0; |
| break; |
| default: |
| break; |
| } |
| g_free(temp_char); |
| end_it: |
| gtk_combo_box_set_active(combo, action); |
| |
| } |
| |
| |
| /* don't free this char */ |
| static const char *_set_job_msg(job_desc_msg_t *job_msg, const char *new_text, |
| int column) |
| { |
| char *type = ""; |
| int temp_int = 0; |
| long long int temp_ll = 0; |
| char *p; |
| char *token; |
| char *sep_char; |
| int j; |
| |
| /* need to clear global_edit_error here (just in case) */ |
| global_edit_error = 0; |
| if (!job_msg) |
| return NULL; |
| |
| switch (column) { |
| case SORTID_ACTION: |
| xfree(got_edit_signal); |
| if (!xstrcasecmp(new_text, "None")) |
| got_edit_signal = NULL; |
| else |
| got_edit_signal = xstrdup(new_text); |
| break; |
| case SORTID_COMMENT: |
| job_msg->comment = xstrdup(new_text); |
| type = "comment"; |
| break; |
| case SORTID_TIMELIMIT: |
| if (!xstrcasecmp(new_text, "infinite")) |
| temp_int = INFINITE; |
| else |
| temp_int = time_str2mins((char *)new_text); |
| |
| type = "timelimit"; |
| if (temp_int <= 0 && temp_int != INFINITE) |
| goto return_error; |
| job_msg->time_limit = (uint32_t)temp_int; |
| break; |
| case SORTID_PRIORITY: |
| if (!xstrcasecmp(new_text, "infinite")) |
| temp_int = INFINITE; |
| else |
| temp_int = strtol(new_text, (char **)NULL, 10); |
| |
| type = "priority"; |
| if ((temp_int < 0) && (temp_int != INFINITE)) |
| goto return_error; |
| job_msg->priority = (uint32_t)temp_int; |
| break; |
| case SORTID_NICE: |
| temp_int = strtol(new_text, (char **)NULL, 10); |
| type = "nice"; |
| if (abs(temp_int) > (int) NICE_OFFSET) { |
| //error("Invalid nice value, must be between " |
| // "-%d and %d", NICE_OFFSET, NICE_OFFSET); |
| goto return_error; |
| } |
| job_msg->nice = NICE_OFFSET + temp_int; |
| break; |
| case SORTID_CPU_REQ: |
| temp_int = strtol(new_text, &p, 10); |
| if (*p == 'k' || *p == 'K') |
| temp_int *= 1024; |
| else if (*p == 'm' || *p == 'M') |
| temp_int *= 1048576; |
| |
| type = "min cpus per node"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->pn_min_cpus = (uint32_t)temp_int; |
| break; |
| case SORTID_TASKS: |
| temp_int = strtol(new_text, (char **)NULL, 10); |
| |
| type = "requested tasks"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->num_tasks = (uint32_t)temp_int; |
| break; |
| case SORTID_CPUS_PER_TASK: |
| temp_int = strtol(new_text, (char **)NULL, 10); |
| |
| type = "cpus per task"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->cpus_per_task = (uint32_t)temp_int; |
| break; |
| case SORTID_RESV_NAME: |
| job_msg->reservation = xstrdup(new_text); |
| type = "reservation name"; |
| break; |
| case SORTID_NODES_MIN: |
| temp_int = strtol(new_text, &p, 10); |
| if (*p == 'k' || *p == 'K') |
| temp_int *= 1024; |
| else if (*p == 'm' || *p == 'M') |
| temp_int *= 1048576; |
| |
| type = "min nodes"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->min_nodes = (uint32_t)temp_int; |
| break; |
| case SORTID_NODES: |
| temp_int = strtol(new_text, &p, 10); |
| if (*p == 'k' || *p == 'K') |
| temp_int *= 1024; |
| else if (*p == 'm' || *p == 'M') |
| temp_int *= 1048576; |
| |
| type = "node count"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->min_nodes = job_msg->max_nodes = (uint32_t)temp_int; |
| break; |
| case SORTID_NODES_MAX: |
| temp_int = strtol(new_text, &p, 10); |
| if (*p == 'k' || *p == 'K') |
| temp_int *= 1024; |
| else if (*p == 'm' || *p == 'M') |
| temp_int *= 1048576; |
| |
| type = "max nodes"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->max_nodes = (uint32_t)temp_int; |
| break; |
| case SORTID_MEM_MIN: |
| temp_ll = strtoll(new_text, &p, 10); |
| if (*p == 'g' || *p == 'G') |
| temp_ll *= 1024; |
| else if (*p == 't' || *p == 'T') |
| temp_ll *= 1048576; |
| |
| p = xstrcasestr((char *)new_text, "tres"); |
| if (p) |
| goto return_error; |
| |
| p = xstrcasestr((char *)new_text, "cpu"); |
| if (p) |
| type = "min memory per cpu"; |
| else |
| type = "min memory per node"; |
| |
| if (temp_ll <= 0) |
| goto return_error; |
| job_msg->pn_min_memory = (uint64_t) temp_ll; |
| if (p) |
| job_msg->pn_min_memory |= MEM_PER_CPU; |
| break; |
| case SORTID_TMP_DISK: |
| temp_int = strtol(new_text, &p, 10); |
| if (*p == 'g' || *p == 'G') |
| temp_int *= 1024; |
| else if (*p == 't' || *p == 'T') |
| temp_int *= 1048576; |
| |
| type = "min tmp disk per node"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->pn_min_tmp_disk = (uint32_t)temp_int; |
| break; |
| case SORTID_PARTITION: |
| job_msg->partition = xstrdup(new_text); |
| type = "partition"; |
| break; |
| case SORTID_NAME: |
| job_msg->name = xstrdup(new_text); |
| type = "name"; |
| break; |
| case SORTID_HET_JOB_ID: |
| job_msg->name = xstrdup(new_text); |
| type = "hetjob jobid"; |
| break; |
| case SORTID_HET_JOB_ID_SET: |
| job_msg->name = xstrdup(new_text); |
| type = "hetjob id set"; |
| break; |
| case SORTID_HET_JOB_OFFSET: |
| job_msg->name = xstrdup(new_text); |
| type = "hetjob offset"; |
| break; |
| case SORTID_WCKEY: |
| job_msg->wckey = xstrdup(new_text); |
| type = "wckey"; |
| break; |
| case SORTID_OVER_SUBSCRIBE: |
| if (!xstrcasecmp(new_text, "yes")) |
| job_msg->shared = 1; |
| else |
| job_msg->shared = 0; |
| |
| type = "oversubscribe"; |
| break; |
| case SORTID_CONTIGUOUS: |
| if (!xstrcasecmp(new_text, "yes")) |
| job_msg->contiguous = 1; |
| else |
| job_msg->contiguous = 0; |
| |
| type = "contiguous"; |
| break; |
| case SORTID_CORE_SPEC: |
| temp_int = strtol(new_text, (char **)NULL, 10); |
| |
| type = "specialized cores"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->core_spec = (uint16_t)temp_int; |
| break; |
| case SORTID_THREAD_SPEC: |
| temp_int = strtol(new_text, (char **)NULL, 10); |
| |
| type = "specialized threads"; |
| if (temp_int <= 0) |
| goto return_error; |
| job_msg->core_spec = (uint16_t)temp_int | CORE_SPEC_THREAD; |
| break; |
| case SORTID_REBOOT: |
| if (!xstrcasecmp(new_text, "yes")) |
| job_msg->reboot = 1; |
| else |
| job_msg->reboot = 0; |
| type = "reboot"; |
| break; |
| case SORTID_REQUEUE: |
| if (!xstrcasecmp(new_text, "yes")) |
| job_msg->requeue = 1; |
| else |
| job_msg->requeue = 0; |
| type = "requeue"; |
| break; |
| case SORTID_NODELIST_REQ: |
| job_msg->req_nodes = xstrdup(new_text); |
| type = "requested nodelist"; |
| break; |
| case SORTID_NODELIST_EXC: |
| job_msg->exc_nodes = xstrdup(new_text); |
| type = "excluded nodelist"; |
| break; |
| case SORTID_FEATURES: |
| job_msg->features = xstrdup(new_text); |
| type = "features"; |
| break; |
| case SORTID_PREFER: |
| job_msg->prefer = xstrdup(new_text); |
| type = "prefer"; |
| break; |
| case SORTID_CPUS_PER_TRES: |
| job_msg->cpus_per_tres = xstrdup(new_text); |
| type = "cpus_per_tres"; |
| break; |
| case SORTID_MEM_PER_TRES: |
| job_msg->mem_per_tres = xstrdup(new_text); |
| type = "mem_per_tres"; |
| break; |
| case SORTID_TRES_PER_JOB: |
| job_msg->tres_per_job = xstrdup(new_text); |
| type = "tres_per_job"; |
| break; |
| case SORTID_TRES_PER_NODE: |
| job_msg->tres_per_node = xstrdup(new_text); |
| type = "tres_per_node"; |
| break; |
| case SORTID_TRES_PER_SOCKET: |
| job_msg->tres_per_socket = xstrdup(new_text); |
| type = "tres_per_socket"; |
| break; |
| case SORTID_TRES_PER_TASK: |
| job_msg->tres_per_task = xstrdup(new_text); |
| type = "tres_per_task"; |
| break; |
| case SORTID_LICENSES: |
| job_msg->licenses = xstrdup(new_text); |
| type = "licenses"; |
| break; |
| case SORTID_MCS_LABEL: |
| job_msg->mcs_label = xstrdup(new_text); |
| type = "mcs_label"; |
| break; |
| case SORTID_ACCOUNT: |
| job_msg->account = xstrdup(new_text); |
| type = "account"; |
| break; |
| case SORTID_BURST_BUFFER: |
| job_msg->burst_buffer = xstrdup(new_text); |
| type = "burst buffer"; |
| break; |
| case SORTID_QOS: |
| job_msg->qos = xstrdup(new_text); |
| type = "qos"; |
| break; |
| case SORTID_COMMAND: |
| type = "script_file"; |
| xfree(job_msg->script); |
| job_msg->script = _read_file(new_text); |
| if (job_msg->script == NULL) |
| goto return_error; |
| if (job_msg->argc) { |
| for (j = 0; j < job_msg->argc; j++) |
| xfree(job_msg->argv[j]); |
| } |
| xfree(job_msg->argv); |
| xfree(job_msg->name); |
| job_msg->argc = 1; |
| job_msg->argv = xmalloc(sizeof(char *) * job_msg->argc); |
| if (new_text[0] == '/') { |
| job_msg->argv[0] = xstrdup(new_text); |
| token = strrchr(new_text, (int) '/'); |
| if (token) |
| job_msg->name = xstrdup(token + 1); |
| } else { |
| job_msg->argv[0] = xmalloc(PATH_MAX); |
| if (!getcwd(job_msg->argv[0], PATH_MAX)) |
| goto return_error; |
| xstrcat(job_msg->argv[0], "/"); |
| xstrcat(job_msg->argv[0], new_text); |
| job_msg->name = xstrdup(new_text); |
| } |
| break; |
| case SORTID_DEPENDENCY: |
| job_msg->dependency = xstrdup(new_text); |
| type = "dependency"; |
| break; |
| case SORTID_TIME_ELIGIBLE: |
| case SORTID_TIME_START: |
| type = "start time"; |
| job_msg->begin_time = parse_time((char *)new_text, 0); |
| if (!job_msg->begin_time) |
| goto return_error; |
| |
| if (job_msg->begin_time < time(NULL)) |
| job_msg->begin_time = time(NULL); |
| break; |
| case SORTID_DEADLINE: |
| type = "deadline"; |
| job_msg->deadline = parse_time((char *)new_text, 0); |
| if (!job_msg->deadline) |
| goto return_error; |
| if (job_msg->deadline < time(NULL)) |
| goto return_error; |
| break; |
| case SORTID_EXTRA: |
| job_msg->extra = xstrdup(new_text); |
| type = "extra"; |
| break; |
| case SORTID_STD_OUT: |
| type = "StdOut"; |
| job_msg->std_out = xstrdup(new_text); |
| break; |
| case SORTID_SWITCHES: |
| type = "switches"; |
| job_msg->req_switch = |
| (uint32_t) strtol(new_text, &sep_char, 10); |
| if (sep_char && sep_char[0] == '@') { |
| job_msg->wait4switch = time_str2mins(sep_char+1) * 60; |
| } |
| break; |
| default: |
| type = "unknown"; |
| break; |
| } |
| |
| if (xstrcmp(type, "unknown")) |
| global_send_update_msg = 1; |
| |
| return type; |
| |
| return_error: |
| global_edit_error = 1; |
| return type; |
| } |
| |
| static void _admin_edit_combo_box_job(GtkComboBox *combo, |
| job_desc_msg_t *job_msg) |
| { |
| GtkTreeModel *model = NULL; |
| GtkTreeIter iter; |
| int column = 0; |
| char *name = NULL; |
| |
| if (!job_msg) |
| return; |
| |
| if (!gtk_combo_box_get_active_iter(combo, &iter)) { |
| g_print("nothing selected\n"); |
| return; |
| } |
| model = gtk_combo_box_get_model(combo); |
| if (!model) { |
| g_print("nothing selected\n"); |
| return; |
| } |
| |
| gtk_tree_model_get(model, &iter, 0, &name, -1); |
| gtk_tree_model_get(model, &iter, 1, &column, -1); |
| |
| _set_job_msg(job_msg, name, column); |
| |
| g_free(name); |
| } |
| |
| static gboolean _admin_focus_out_job(GtkEntry *entry, |
| GdkEventFocus *event, |
| job_desc_msg_t *job_msg) |
| { |
| if (global_entry_changed) { |
| const char *col_name = NULL; |
| int type = gtk_entry_get_max_length(entry); |
| const char *name = gtk_entry_get_text(entry); |
| type -= DEFAULT_ENTRY_LENGTH; |
| |
| col_name = _set_job_msg(job_msg, name, type); |
| if (global_edit_error) { |
| if (global_edit_error_msg) |
| g_free(global_edit_error_msg); |
| global_edit_error_msg = g_strdup_printf( |
| "Job %d %s can't be set to %s", |
| job_msg->job_id, |
| col_name, |
| name); |
| } |
| global_entry_changed = 0; |
| } |
| return false; |
| } |
| |
| static GtkWidget *_admin_full_edit_job(job_desc_msg_t *job_msg, |
| GtkTreeModel *model, GtkTreeIter *iter) |
| { |
| GtkScrolledWindow *window = create_scrolled_window(); |
| GtkBin *bin = NULL; |
| GtkViewport *view = NULL; |
| GtkTable *table = NULL; |
| int i = 0, row = 0; |
| display_data_t *display_data = display_data_job; |
| |
| gtk_scrolled_window_set_policy(window, |
| GTK_POLICY_NEVER, |
| GTK_POLICY_AUTOMATIC); |
| bin = GTK_BIN(&window->container); |
| view = GTK_VIEWPORT(bin->child); |
| bin = GTK_BIN(&view->bin); |
| table = GTK_TABLE(bin->child); |
| gtk_table_resize(table, SORTID_CNT, 2); |
| |
| gtk_table_set_homogeneous(table, false); |
| |
| for(i = 0; i < SORTID_CNT; i++) { |
| while (display_data++) { |
| if (display_data->id == -1) |
| break; |
| if (!display_data->name) |
| continue; |
| if (display_data->id != i) |
| continue; |
| display_admin_edit( |
| table, job_msg, &row, model, iter, |
| display_data, |
| G_CALLBACK(_admin_edit_combo_box_job), |
| G_CALLBACK(_admin_focus_out_job), |
| _set_active_combo_job); |
| break; |
| } |
| display_data = display_data_job; |
| } |
| gtk_table_resize(table, row, 2); |
| |
| return GTK_WIDGET(window); |
| } |
| |
| static int _nodes_in_list(char *node_list) |
| { |
| hostset_t *host_set = hostset_create(node_list); |
| int count = hostset_count(host_set); |
| hostset_destroy(host_set); |
| return count; |
| } |
| |
| /* this needs to be freed by xfree() */ |
| static void _convert_char_to_job_and_step(const char *data, |
| int *jobid, int *stepid) |
| { |
| int i = 0; |
| |
| if (!data) |
| return; |
| *jobid = atoi(data); |
| *stepid = NO_VAL; |
| while (data[i]) { |
| if (data[i] == '.') { |
| i++; |
| if (data[i]) |
| *stepid = atoi(&data[i]); |
| break; |
| } |
| i++; |
| } |
| |
| return; |
| } |
| |
| static void _layout_job_record(GtkTreeView *treeview, |
| sview_job_info_t *sview_job_info_ptr, |
| int update) |
| { |
| char *nodes = NULL, *uname = NULL; |
| const char *reason = NULL; |
| char *group; |
| char tmp_char[256]; |
| char time_buf[32]; |
| char tmp1[128]; |
| char running_char[50]; |
| time_t now_time = time(NULL); |
| int suspend_secs = 0; |
| job_info_t *job_ptr = sview_job_info_ptr->job_ptr; |
| uint16_t term_code = 0, term_sig = 0; |
| uint64_t min_mem = 0; |
| |
| GtkTreeIter iter; |
| GtkTreeStore *treestore = |
| GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); |
| |
| if (!treestore) |
| return; |
| |
| if (!job_ptr->nodes || IS_JOB_PENDING(job_ptr) || |
| !xstrcasecmp(job_ptr->nodes,"waiting...")) { |
| sprintf(running_char,"00:00:00"); |
| nodes = xstrdup("waiting..."); |
| } else { |
| if (IS_JOB_SUSPENDED(job_ptr)) |
| now_time = job_ptr->pre_sus_time; |
| else { |
| if (!IS_JOB_RUNNING(job_ptr) && |
| (job_ptr->end_time != 0)) |
| now_time = job_ptr->end_time; |
| if (job_ptr->suspend_time) { |
| now_time = (time_t) |
| (difftime(now_time, |
| job_ptr->suspend_time) |
| + job_ptr->pre_sus_time); |
| } else |
| now_time = (time_t)difftime( |
| now_time, job_ptr->start_time); |
| } |
| suspend_secs = (time(NULL) - job_ptr->start_time) - now_time; |
| secs2time_str(now_time, running_char, sizeof(running_char)); |
| |
| nodes = slurm_sort_node_list_str(sview_job_info_ptr->nodes); |
| } |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_ACCOUNT), |
| job_ptr->account); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%s:%u", |
| job_ptr->alloc_node, job_ptr->alloc_sid); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_ALLOC_NODE), |
| tmp_char); |
| |
| if (job_ptr->array_task_str || |
| (job_ptr->array_task_id != NO_VAL)) { |
| snprintf(tmp_char, sizeof(tmp_char), "%u", |
| job_ptr->array_job_id); |
| } else { |
| snprintf(tmp_char, sizeof(tmp_char), "N/A"); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_ARRAY_JOB_ID), |
| tmp_char); |
| |
| if (job_ptr->array_task_str) { |
| snprintf(tmp_char, sizeof(tmp_char), "[%s]", |
| job_ptr->array_task_str); |
| } else if (job_ptr->array_task_id != NO_VAL) { |
| snprintf(tmp_char, sizeof(tmp_char), "%u", |
| job_ptr->array_task_id); |
| } else { |
| snprintf(tmp_char, sizeof(tmp_char), "N/A"); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_ARRAY_TASK_ID), |
| tmp_char); |
| |
| if (job_ptr->batch_flag) |
| sprintf(tmp_char, "yes"); |
| else |
| sprintf(tmp_char, "no"); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_BATCH), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_BATCH_HOST), |
| job_ptr->batch_host); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_BURST_BUFFER), |
| job_ptr->burst_buffer); |
| |
| if (job_ptr->cluster) { |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CLUSTER_NAME), |
| job_ptr->cluster); |
| } |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_COMMAND), |
| job_ptr->command); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_COMMENT), |
| job_ptr->comment); |
| |
| if (job_ptr->contiguous) |
| sprintf(tmp_char, "yes"); |
| else |
| sprintf(tmp_char, "no"); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CONTIGUOUS), |
| tmp_char); |
| |
| if ((job_ptr->core_spec == NO_VAL16) || |
| (job_ptr->core_spec & CORE_SPEC_THREAD)) { |
| sprintf(tmp_char, "N/A"); |
| } else { |
| sprintf(tmp_char, "%u", job_ptr->core_spec); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CORE_SPEC), |
| tmp_char); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->num_cpus); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CPUS), |
| tmp_char); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->max_cpus); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CPU_MAX), |
| tmp_char); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->num_cpus); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CPU_MIN), |
| tmp_char); |
| |
| if (job_ptr->cpus_per_task == NO_VAL16) |
| sprintf(tmp_char, "N/A"); |
| else |
| sprintf(tmp_char, "%u", job_ptr->cpus_per_task); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CPUS_PER_TASK), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CPUS_PER_TRES), |
| job_ptr->cpus_per_tres); |
| |
| if (job_ptr->deadline) |
| slurm_make_time_str((time_t *)&job_ptr->deadline, tmp_char, |
| sizeof(tmp_char)); |
| else |
| sprintf(tmp_char, "N/A"); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_DEADLINE), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_DEPENDENCY), |
| job_ptr->dependency); |
| |
| if (WIFEXITED(job_ptr->derived_ec)) |
| term_code = WEXITSTATUS(job_ptr->derived_ec); |
| else |
| term_code = 0; |
| if (WIFSIGNALED(job_ptr->derived_ec)) |
| term_sig = WTERMSIG(job_ptr->derived_ec); |
| else |
| term_sig = 0; |
| snprintf(tmp_char, sizeof(tmp_char), "%u:%u", term_code, term_sig); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_DERIVED_EC), |
| tmp_char); |
| |
| if (WIFEXITED(job_ptr->exit_code)) |
| term_code = WEXITSTATUS(job_ptr->exit_code); |
| else |
| term_code = 0; |
| if (WIFSIGNALED(job_ptr->exit_code)) |
| term_sig = WTERMSIG(job_ptr->exit_code); |
| else |
| term_sig = 0; |
| snprintf(tmp_char, sizeof(tmp_char), "%u:%u", term_code, term_sig); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_EXIT_CODE), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_EXTRA), |
| job_ptr->extra); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_FEATURES), |
| job_ptr->features); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_PREFER), |
| job_ptr->prefer); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_FED_ACTIVE_SIBS), |
| job_ptr->fed_siblings_active_str); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_FED_ORIGIN), |
| job_ptr->fed_origin_str); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_FED_VIABLE_SIBS), |
| job_ptr->fed_siblings_viable_str); |
| |
| /* "gres" replaced by "tres_per_node" in v18.08 */ |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_GRES), |
| job_ptr->tres_per_node); |
| |
| group = gid_to_string(job_ptr->group_id); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_GROUP_ID), |
| group); |
| xfree(group); |
| |
| if (job_ptr->array_task_str) { |
| snprintf(tmp_char, sizeof(tmp_char), "%u_[%s] (%u)", |
| job_ptr->array_job_id, job_ptr->array_task_str, |
| job_ptr->job_id); |
| } else if (job_ptr->array_task_id != NO_VAL) { |
| snprintf(tmp_char, sizeof(tmp_char), "%u_%u (%u)", |
| job_ptr->array_job_id, job_ptr->array_task_id, |
| job_ptr->job_id); |
| } else if (job_ptr->het_job_id) { |
| snprintf(tmp_char, sizeof(tmp_char), "%u+%u (%u)", |
| job_ptr->het_job_id, |
| job_ptr->het_job_offset, |
| job_ptr->job_id); |
| } else { |
| snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->job_id); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_JOBID), |
| tmp_char); |
| |
| slurm_make_time_str(&job_ptr->last_sched_eval, tmp_char, |
| sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_LAST_SCHED_EVAL), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_LICENSES), |
| job_ptr->licenses); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_MCS_LABEL), |
| (job_ptr->mcs_label==NULL) ? "N/A" : |
| job_ptr->mcs_label); |
| |
| convert_num_unit((float)job_ptr->pn_min_cpus, tmp_char, |
| sizeof(tmp_char), UNIT_NONE, NO_VAL, |
| working_sview_config.convert_flags); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CPU_REQ), |
| tmp_char); |
| |
| min_mem = job_ptr->pn_min_memory; |
| if (min_mem & MEM_PER_CPU) |
| min_mem &= (~MEM_PER_CPU); |
| |
| if (min_mem > 0) { |
| int len; |
| convert_num_unit((float)min_mem, tmp_char, sizeof(tmp_char), |
| UNIT_MEGA, NO_VAL, |
| working_sview_config.convert_flags); |
| len = strlen(tmp_char); |
| if (job_ptr->mem_per_tres) { |
| sprintf(tmp_char+len, " Per TRES"); |
| } else if (job_ptr->pn_min_memory & MEM_PER_CPU) |
| sprintf(tmp_char+len, " Per CPU"); |
| else |
| sprintf(tmp_char+len, " Per Node"); |
| } else |
| sprintf(tmp_char, " "); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_MEM_MIN), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_MEM_PER_TRES), |
| job_ptr->mem_per_tres); |
| |
| if (job_ptr->pn_min_tmp_disk > 0) |
| convert_num_unit((float)job_ptr->pn_min_tmp_disk, tmp_char, |
| sizeof(tmp_char), UNIT_MEGA, NO_VAL, |
| working_sview_config.convert_flags); |
| else |
| sprintf(tmp_char, " "); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TMP_DISK), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NAME), |
| job_ptr->name); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NETWORK), |
| job_ptr->network); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%"PRIi64, |
| (((int64_t)job_ptr->nice) - NICE_OFFSET)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NICE), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODELIST), |
| nodes); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODELIST_EXC), |
| job_ptr->exc_nodes); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODELIST_REQ), |
| job_ptr->req_nodes); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODELIST_SCHED), |
| job_ptr->sched_nodes); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%u", |
| sview_job_info_ptr->node_cnt); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODES), |
| tmp_char); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->max_nodes); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODES_MAX), |
| tmp_char); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%u", |
| sview_job_info_ptr->node_cnt); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODES_MIN), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_OVER_SUBSCRIBE), |
| job_share_string(job_ptr->shared)); |
| |
| if (job_ptr->het_job_id) { |
| snprintf(tmp_char, sizeof(tmp_char), "%u", |
| job_ptr->het_job_id); |
| } else { |
| snprintf(tmp_char, sizeof(tmp_char), "N/A"); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_HET_JOB_ID), |
| tmp_char); |
| |
| if (job_ptr->het_job_offset) { |
| snprintf(tmp_char, sizeof(tmp_char), "%u", |
| job_ptr->het_job_offset); |
| } else { |
| snprintf(tmp_char, sizeof(tmp_char), "N/A"); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_HET_JOB_OFFSET), |
| tmp_char); |
| |
| if (job_ptr->het_job_id_set) { |
| snprintf(tmp_char, sizeof(tmp_char), "%s", |
| job_ptr->het_job_id_set); |
| } else { |
| snprintf(tmp_char, sizeof(tmp_char), "N/A"); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_HET_JOB_ID_SET), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_PARTITION), |
| job_ptr->partition); |
| |
| if (job_ptr->preempt_time) { |
| slurm_make_time_str((time_t *)&job_ptr->preempt_time, tmp_char, |
| sizeof(tmp_char)); |
| } else |
| sprintf(tmp_char, "N/A"); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_PREEMPT_TIME), |
| tmp_char); |
| |
| sprintf(tmp_char, "%u", job_ptr->priority); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_PRIORITY), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_QOS), |
| job_ptr->qos); |
| |
| if (job_ptr->state_desc) |
| reason = job_ptr->state_desc; |
| else |
| reason = job_state_reason_string(job_ptr->state_reason); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_REASON), reason); |
| |
| if (job_ptr->reboot) |
| sprintf(tmp_char, "yes"); |
| else |
| sprintf(tmp_char, "no"); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_REBOOT), |
| tmp_char); |
| |
| if (job_ptr->requeue) |
| sprintf(tmp_char, "yes"); |
| else |
| sprintf(tmp_char, "no"); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_REQUEUE), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_RESV_NAME), |
| job_ptr->resv_name); |
| |
| snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->restart_cnt); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_RESTARTS), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_STATE), |
| job_state_string(job_ptr->job_state)); |
| |
| slurm_get_job_stderr(tmp1, sizeof(tmp1), job_ptr); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_STD_ERR), |
| tmp1); |
| |
| slurm_get_job_stdin(tmp1, sizeof(tmp1), job_ptr); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_STD_IN), |
| tmp1); |
| |
| slurm_get_job_stdout(tmp1, sizeof(tmp1), job_ptr); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_STD_OUT), |
| tmp1); |
| |
| secs2time_str((time_t) job_ptr->wait4switch, time_buf, |
| sizeof(time_buf)); |
| snprintf(tmp_char, sizeof(tmp_char), "%u@%s", |
| job_ptr->req_switch, time_buf); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_SWITCHES), |
| tmp_char); |
| |
| if ((job_ptr->core_spec == NO_VAL16) || |
| ((job_ptr->core_spec & CORE_SPEC_THREAD) == 0)) { |
| sprintf(tmp_char, "N/A"); |
| } else { |
| sprintf(tmp_char, "%u", |
| job_ptr->core_spec & (~CORE_SPEC_THREAD)); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_THREAD_SPEC), |
| tmp_char); |
| |
| slurm_make_time_str((time_t *)&job_ptr->accrue_time, tmp_char, |
| sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_ACCRUE), |
| tmp_char); |
| slurm_make_time_str((time_t *)&job_ptr->eligible_time, tmp_char, |
| sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_ELIGIBLE), |
| tmp_char); |
| if ((job_ptr->time_limit == INFINITE) && |
| (job_ptr->end_time > time(NULL))) |
| sprintf(tmp_char, "Unknown"); |
| else |
| slurm_make_time_str((time_t *)&job_ptr->end_time, tmp_char, |
| sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_END), |
| tmp_char); |
| |
| if (job_ptr->time_limit == NO_VAL) |
| sprintf(tmp_char, "Partition Limit"); |
| else if (job_ptr->time_limit == INFINITE) |
| sprintf(tmp_char, "Infinite"); |
| else |
| secs2time_str((job_ptr->time_limit * 60), |
| tmp_char, sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIMELIMIT), |
| tmp_char); |
| |
| if (job_ptr->resize_time) { |
| slurm_make_time_str((time_t *)&job_ptr->resize_time, tmp_char, |
| sizeof(tmp_char)); |
| } else |
| sprintf(tmp_char, "N/A"); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_RESIZE), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_RUNNING), |
| running_char); |
| |
| slurm_make_time_str((time_t *)&job_ptr->start_time, tmp_char, |
| sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_START), |
| tmp_char); |
| slurm_make_time_str((time_t *)&job_ptr->submit_time, tmp_char, |
| sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_SUBMIT), |
| tmp_char); |
| secs2time_str(suspend_secs, tmp_char, sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_SUSPEND), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_ALLOC), |
| job_ptr->tres_alloc_str); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_BIND), |
| job_ptr->tres_bind); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_FREQ), |
| job_ptr->tres_freq); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_PER_JOB), |
| job_ptr->tres_per_job); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_PER_NODE), |
| job_ptr->tres_per_node); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_PER_SOCKET), |
| job_ptr->tres_per_socket); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_PER_TASK), |
| job_ptr->tres_per_task); |
| |
| uname = uid_to_string_cached((uid_t)job_ptr->user_id); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_USER_ID), uname); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_WCKEY), |
| job_ptr->wckey); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_WORKDIR), |
| job_ptr->work_dir); |
| |
| xfree(nodes); |
| } |
| |
| static void _update_job_record(sview_job_info_t *sview_job_info_ptr, |
| GtkTreeStore *treestore, |
| GtkTreeIter *iter, bool check_task, |
| bool handle_pending) |
| { |
| char tmp_array_job_id[20], tmp_array_task_id[20]; |
| char tmp_time_run[40], tmp_time_resize[256], tmp_time_submit[256]; |
| char tmp_time_elig[256], tmp_time_start[256], tmp_time_end[256]; |
| char tmp_time_sus[40], tmp_time_limit[40], tmp_alloc_node[40]; |
| char tmp_exit[40], tmp_derived_ec[40]; |
| char tmp_cpu_cnt[40], tmp_node_cnt[40], tmp_disk[40]; |
| char tmp_cpus_max[40], tmp_mem_min[40], tmp_cpu_req[40]; |
| char tmp_nodes_min[40], tmp_nodes_max[40], tmp_cpus_per_task[40]; |
| char tmp_prio[40], tmp_nice[40], tmp_preempt_time[256]; |
| char tmp_rqswitch[40], tmp_core_spec[40], tmp_job_id[40]; |
| char tmp_std_err[128], tmp_std_in[128], tmp_std_out[128]; |
| char tmp_thread_spec[40], tmp_time_deadline[256], tmp_het_job_id[40]; |
| char tmp_het_job_id_set[40], tmp_het_job_offset[40]; |
| char tmp_time_accrue[256]; |
| char *tmp_batch, *tmp_cont, *tmp_requeue, *tmp_uname, *tmp_gname; |
| char *tmp_reboot,*tmp_nodes; |
| const char *tmp_reason; |
| char time_buf[32]; |
| time_t now_time = time(NULL); |
| int suspend_secs = 0; |
| GtkTreeIter step_iter; |
| job_info_t *job_ptr = sview_job_info_ptr->job_ptr; |
| uint16_t term_code = 0, term_sig = 0; |
| uint64_t min_mem = 0; |
| |
| if (!iter) |
| iter = &sview_job_info_ptr->iter_ptr; |
| |
| snprintf(tmp_alloc_node, sizeof(tmp_alloc_node), "%s:%u", |
| job_ptr->alloc_node, job_ptr->alloc_sid); |
| |
| /* |
| * These need to be set up first, or they could be NULL when |
| * they need to be set. Since we do a xstrcmp on these later |
| * we need to make sure they are exactly the same (length wise). |
| */ |
| if (!sview_job_info_ptr->task_hl_str && sview_job_info_ptr->task_hl) { |
| sview_job_info_ptr->task_hl_str = |
| hostlist_ranged_string_xmalloc( |
| sview_job_info_ptr->task_hl); |
| if (!job_ptr->het_job_id) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%u_%s", |
| job_ptr->array_job_id, |
| sview_job_info_ptr->task_hl_str); |
| } else { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%u+%s", |
| job_ptr->het_job_id, |
| sview_job_info_ptr->task_hl_str); |
| } |
| xfree(sview_job_info_ptr->task_hl_str); |
| sview_job_info_ptr->task_hl_str = xstrdup(tmp_job_id); |
| } |
| |
| if (!sview_job_info_ptr->task_pending_hl_str |
| && sview_job_info_ptr->task_pending_hl) { |
| sview_job_info_ptr->task_pending_hl_str = |
| hostlist_ranged_string_xmalloc( |
| sview_job_info_ptr->task_pending_hl); |
| if (!job_ptr->het_job_id) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%u_%s", |
| job_ptr->array_job_id, |
| sview_job_info_ptr->task_pending_hl_str); |
| } else { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%u+%s", |
| job_ptr->het_job_id, |
| sview_job_info_ptr->task_pending_hl_str); |
| } |
| xfree(sview_job_info_ptr->task_pending_hl_str); |
| sview_job_info_ptr->task_pending_hl_str = |
| xstrdup(tmp_job_id); |
| } |
| |
| if (handle_pending && |
| (job_ptr->het_job_id || job_ptr->array_job_id)) { |
| if (job_ptr->array_task_str || |
| (job_ptr->array_task_id != NO_VAL)) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%s", |
| sview_job_info_ptr->task_pending_hl_str); |
| snprintf(tmp_array_job_id, |
| sizeof(tmp_array_job_id), "N/A"); |
| snprintf(tmp_array_task_id, |
| sizeof(tmp_array_task_id), "%s", |
| sview_job_info_ptr->task_pending_hl_str); |
| } else if (job_ptr->het_job_id) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%s", |
| sview_job_info_ptr->task_pending_hl_str); |
| } |
| } else if (check_task && |
| (job_ptr->het_job_id || job_ptr->array_job_id)) { |
| if (job_ptr->array_task_str || |
| (job_ptr->array_task_id != NO_VAL)) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%s", |
| sview_job_info_ptr->task_hl_str); |
| snprintf(tmp_array_job_id, |
| sizeof(tmp_array_job_id), "N/A"); |
| snprintf(tmp_array_task_id, |
| sizeof(tmp_array_task_id), "%s", |
| sview_job_info_ptr->task_hl_str); |
| } else if (job_ptr->het_job_id) |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%s", |
| sview_job_info_ptr->task_hl_str); |
| } else if (job_ptr->array_task_str) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%s", |
| sview_job_info_ptr->job_id_str); |
| snprintf(tmp_array_job_id, sizeof(tmp_array_job_id), "%u", |
| job_ptr->array_job_id); |
| snprintf(tmp_array_task_id, sizeof(tmp_array_task_id), "[%s]", |
| job_ptr->array_task_str); |
| } else if (job_ptr->array_task_id != NO_VAL) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%s", |
| sview_job_info_ptr->job_id_str); |
| snprintf(tmp_array_job_id, sizeof(tmp_array_job_id), "%u", |
| job_ptr->array_job_id); |
| snprintf(tmp_array_task_id, sizeof(tmp_array_task_id), "%u", |
| job_ptr->array_task_id); |
| } else if (job_ptr->het_job_id) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%s", |
| sview_job_info_ptr->job_id_str); |
| snprintf(tmp_het_job_id, sizeof(tmp_het_job_id), |
| "%u", job_ptr->het_job_id); |
| snprintf(tmp_het_job_id_set, sizeof(tmp_het_job_id_set), |
| "%s", job_ptr->het_job_id_set); |
| snprintf(tmp_het_job_offset, sizeof(tmp_het_job_offset), |
| "%u", job_ptr->het_job_offset); |
| } else { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%s", |
| sview_job_info_ptr->job_id_str); |
| } |
| |
| |
| if (!job_ptr->het_job_id) { |
| snprintf(tmp_het_job_id, |
| sizeof(tmp_het_job_id), "N/A"); |
| snprintf(tmp_het_job_id_set, |
| sizeof(tmp_het_job_id_set), "N/A"); |
| snprintf(tmp_het_job_offset, |
| sizeof(tmp_het_job_offset), "N/A"); |
| } |
| |
| if (!job_ptr->array_job_id) { |
| snprintf(tmp_array_job_id, |
| sizeof(tmp_array_job_id), "N/A"); |
| snprintf(tmp_array_task_id, |
| sizeof(tmp_array_task_id), "N/A"); |
| } |
| |
| if (job_ptr->batch_flag) |
| tmp_batch = "yes"; |
| else |
| tmp_batch = "no"; |
| |
| if (job_ptr->contiguous) |
| tmp_cont = "yes"; |
| else |
| tmp_cont = "no"; |
| |
| if ((job_ptr->core_spec == NO_VAL16) || |
| (job_ptr->core_spec & CORE_SPEC_THREAD)) { |
| sprintf(tmp_core_spec, "N/A"); |
| } else { |
| sprintf(tmp_core_spec, "%u", job_ptr->core_spec); |
| } |
| if ((job_ptr->core_spec == NO_VAL16) || |
| ((job_ptr->core_spec & CORE_SPEC_THREAD) == 0)) { |
| sprintf(tmp_thread_spec, "N/A"); |
| } else { |
| sprintf(tmp_thread_spec, "%u", |
| job_ptr->core_spec & (~CORE_SPEC_THREAD)); |
| } |
| |
| |
| if (job_ptr->cpus_per_task == NO_VAL16) |
| sprintf(tmp_cpus_per_task, "N/A"); |
| else |
| sprintf(tmp_cpus_per_task, "%u", job_ptr->cpus_per_task); |
| |
| snprintf(tmp_cpu_cnt, sizeof(tmp_cpu_cnt), "%u", job_ptr->num_cpus); |
| convert_num_unit((float)job_ptr->pn_min_cpus, tmp_cpu_req, |
| sizeof(tmp_cpu_req), UNIT_NONE, NO_VAL, |
| working_sview_config.convert_flags); |
| |
| snprintf(tmp_cpus_max, sizeof(tmp_cpus_max), "%u", |
| job_ptr->max_cpus); |
| convert_num_unit((float)job_ptr->pn_min_tmp_disk, tmp_disk, |
| sizeof(tmp_disk), UNIT_MEGA, NO_VAL, |
| working_sview_config.convert_flags); |
| |
| if (WIFEXITED(job_ptr->derived_ec)) |
| term_code = WEXITSTATUS(job_ptr->derived_ec); |
| else |
| term_code = 0; |
| if (WIFSIGNALED(job_ptr->derived_ec)) |
| term_sig = WTERMSIG(job_ptr->derived_ec); |
| else |
| term_sig = 0; |
| snprintf(tmp_derived_ec, sizeof(tmp_derived_ec), "%u:%u", |
| term_code, term_sig); |
| |
| if (WIFEXITED(job_ptr->exit_code)) |
| term_code = WEXITSTATUS(job_ptr->exit_code); |
| else |
| term_code = 0; |
| if (WIFSIGNALED(job_ptr->exit_code)) |
| term_sig = WTERMSIG(job_ptr->exit_code); |
| else |
| term_sig = 0; |
| snprintf(tmp_exit, sizeof(tmp_exit), "%u:%u", term_code, term_sig); |
| |
| tmp_gname = gid_to_string(job_ptr->group_id); |
| |
| min_mem = job_ptr->pn_min_memory; |
| if (min_mem & MEM_PER_CPU) |
| min_mem &= (~MEM_PER_CPU); |
| |
| if (min_mem > 0) { |
| int len; |
| convert_num_unit((float)min_mem, tmp_mem_min, |
| sizeof(tmp_mem_min), UNIT_MEGA, NO_VAL, |
| working_sview_config.convert_flags); |
| len = strlen(tmp_mem_min); |
| if (job_ptr->mem_per_tres) { |
| sprintf(tmp_mem_min+len, " Per TRES"); |
| } else if (job_ptr->pn_min_memory & MEM_PER_CPU) |
| sprintf(tmp_mem_min+len, " Per CPU"); |
| else |
| sprintf(tmp_mem_min+len, " Per Node"); |
| } else |
| sprintf(tmp_mem_min, " "); |
| |
| sprintf(tmp_node_cnt, "%u", sview_job_info_ptr->node_cnt); |
| |
| sprintf(tmp_nodes_min, "%u", sview_job_info_ptr->node_cnt); |
| |
| if (job_ptr->state_desc) |
| tmp_reason = job_ptr->state_desc; |
| else |
| tmp_reason = job_state_reason_string(job_ptr->state_reason); |
| |
| if (job_ptr->reboot) |
| tmp_reboot = "yes"; |
| else |
| tmp_reboot = "no"; |
| |
| if (job_ptr->requeue) |
| tmp_requeue = "yes"; |
| else |
| tmp_requeue = "no"; |
| |
| snprintf(tmp_nice, sizeof(tmp_nice), "%"PRIi64, |
| (((int64_t)job_ptr->nice) - NICE_OFFSET)); |
| |
| if (!job_ptr->nodes || IS_JOB_PENDING(job_ptr) || |
| !xstrcasecmp(job_ptr->nodes,"waiting...")) { |
| sprintf(tmp_time_run,"00:00:00"); |
| tmp_nodes = xstrdup("waiting..."); |
| } else { |
| if (IS_JOB_SUSPENDED(job_ptr)) |
| now_time = job_ptr->pre_sus_time; |
| else { |
| if (!IS_JOB_RUNNING(job_ptr) && |
| (job_ptr->end_time != 0)) |
| now_time = job_ptr->end_time; |
| if (job_ptr->suspend_time) { |
| now_time = (time_t) |
| (difftime(now_time, |
| job_ptr->suspend_time) |
| + job_ptr->pre_sus_time); |
| } else |
| now_time = (time_t)difftime( |
| now_time, job_ptr->start_time); |
| } |
| suspend_secs = (time(NULL) - job_ptr->start_time) - now_time; |
| secs2time_str(now_time, tmp_time_run, sizeof(tmp_time_run)); |
| tmp_nodes = slurm_sort_node_list_str(sview_job_info_ptr->nodes); |
| } |
| |
| if (job_ptr->max_nodes > 0) |
| sprintf(tmp_nodes_max, "%u", sview_job_info_ptr->node_cnt); |
| else |
| tmp_nodes_max[0] = '\0'; |
| |
| sprintf(tmp_prio, "%u", job_ptr->priority); |
| |
| slurm_make_time_str((time_t *)&job_ptr->accrue_time, tmp_time_accrue, |
| sizeof(tmp_time_accrue)); |
| |
| slurm_make_time_str((time_t *)&job_ptr->eligible_time, tmp_time_elig, |
| sizeof(tmp_time_elig)); |
| |
| if ((job_ptr->time_limit == INFINITE) && |
| (job_ptr->end_time > time(NULL))) |
| sprintf(tmp_time_end, "Unknown"); |
| else |
| slurm_make_time_str((time_t *)&job_ptr->end_time, tmp_time_end, |
| sizeof(tmp_time_end)); |
| |
| if (job_ptr->time_limit == NO_VAL) |
| sprintf(tmp_time_limit, "Partition Limit"); |
| else if (job_ptr->time_limit == INFINITE) |
| sprintf(tmp_time_limit, "Infinite"); |
| else |
| secs2time_str((job_ptr->time_limit * 60), |
| tmp_time_limit, sizeof(tmp_time_limit)); |
| |
| if (job_ptr->preempt_time) { |
| slurm_make_time_str((time_t *)&job_ptr->preempt_time, |
| tmp_preempt_time, sizeof(tmp_preempt_time)); |
| } else |
| sprintf(tmp_preempt_time, "N/A"); |
| |
| if (job_ptr->resize_time) { |
| slurm_make_time_str((time_t *)&job_ptr->resize_time, |
| tmp_time_resize, sizeof(tmp_time_resize)); |
| } else |
| sprintf(tmp_time_resize, "N/A"); |
| |
| slurm_make_time_str((time_t *)&job_ptr->start_time, tmp_time_start, |
| sizeof(tmp_time_start)); |
| |
| slurm_make_time_str((time_t *)&job_ptr->submit_time, tmp_time_submit, |
| sizeof(tmp_time_submit)); |
| |
| if (job_ptr->deadline) |
| slurm_make_time_str((time_t *)&job_ptr->deadline, |
| tmp_time_deadline, |
| sizeof(tmp_time_deadline)); |
| else |
| sprintf(tmp_time_deadline, "N/A"); |
| |
| slurm_get_job_stderr(tmp_std_err, sizeof(tmp_std_err), job_ptr); |
| |
| slurm_get_job_stdin(tmp_std_in, sizeof(tmp_std_in), job_ptr); |
| |
| slurm_get_job_stdout(tmp_std_out, sizeof(tmp_std_out), job_ptr); |
| |
| secs2time_str(suspend_secs, tmp_time_sus, sizeof(tmp_time_sus)); |
| |
| if (job_ptr->req_switch != NO_VAL) { |
| if (job_ptr->wait4switch != NO_VAL) { |
| secs2time_str((time_t) job_ptr->wait4switch, time_buf, |
| sizeof(time_buf)); |
| sprintf(tmp_rqswitch, "%u@%s", |
| job_ptr->req_switch, time_buf); |
| } else { |
| sprintf(tmp_rqswitch, "%u", job_ptr->req_switch); |
| } |
| |
| } else { |
| sprintf(tmp_rqswitch, "N/A"); |
| } |
| |
| tmp_uname = uid_to_string_cached((uid_t)job_ptr->user_id); |
| |
| if ((handle_pending || check_task) && |
| (job_ptr->array_task_str || (job_ptr->array_task_id != NO_VAL) || |
| job_ptr->het_job_id)) { |
| gtk_tree_store_set(treestore, iter, |
| SORTID_ACCOUNT, job_ptr->account, |
| SORTID_ALLOC, 1, |
| SORTID_ALLOC_NODE, tmp_alloc_node, |
| SORTID_ARRAY_JOB_ID, tmp_array_job_id, |
| SORTID_ARRAY_TASK_ID,tmp_array_task_id, |
| SORTID_BATCH, tmp_batch, |
| SORTID_BATCH_HOST, job_ptr->batch_host, |
| SORTID_BURST_BUFFER, job_ptr->burst_buffer, |
| SORTID_CLUSTER_NAME, job_ptr->cluster, |
| SORTID_COLOR, |
| sview_colors[sview_job_info_ptr->color_inx], |
| SORTID_COLOR_INX, |
| sview_job_info_ptr->color_inx, |
| SORTID_COMMAND, job_ptr->command, |
| SORTID_COMMENT, job_ptr->comment, |
| SORTID_CONTIGUOUS, tmp_cont, |
| SORTID_EXTRA, job_ptr->extra, |
| SORTID_JOBID, tmp_job_id, |
| SORTID_JOBID_FORMATTED, tmp_job_id, |
| SORTID_HET_JOB_ID, tmp_het_job_id, |
| SORTID_HET_JOB_ID_SET, tmp_het_job_id_set, |
| SORTID_HET_JOB_OFFSET, tmp_het_job_offset, |
| SORTID_PARTITION, job_ptr->partition, |
| SORTID_UPDATED, 1, |
| SORTID_USER_ID, tmp_uname, |
| -1); |
| if (handle_pending) |
| gtk_tree_store_set(treestore, iter, |
| SORTID_ACCOUNT, job_ptr->account, |
| SORTID_STATE, |
| job_state_string(JOB_PENDING), |
| -1); |
| } else { |
| gtk_tree_store_set(treestore, iter, |
| SORTID_ACCOUNT, job_ptr->account, |
| SORTID_ALLOC, 1, |
| SORTID_ALLOC_NODE, tmp_alloc_node, |
| SORTID_ARRAY_JOB_ID, tmp_array_job_id, |
| SORTID_ARRAY_TASK_ID,tmp_array_task_id, |
| SORTID_BATCH, tmp_batch, |
| SORTID_BATCH_HOST, job_ptr->batch_host, |
| SORTID_BURST_BUFFER, job_ptr->burst_buffer, |
| SORTID_CLUSTER_NAME, job_ptr->cluster, |
| SORTID_COLOR, |
| sview_colors[sview_job_info_ptr->color_inx], |
| SORTID_COLOR_INX, |
| sview_job_info_ptr->color_inx, |
| SORTID_COMMAND, job_ptr->command, |
| SORTID_COMMENT, job_ptr->comment, |
| SORTID_CONTIGUOUS, tmp_cont, |
| SORTID_CORE_SPEC, tmp_core_spec, |
| SORTID_CPUS, tmp_cpu_cnt, |
| SORTID_CPU_MAX, tmp_cpus_max, |
| SORTID_CPU_MIN, tmp_cpu_cnt, |
| SORTID_CPUS_PER_TASK,tmp_cpus_per_task, |
| SORTID_CPUS_PER_TRES,job_ptr->cpus_per_tres, |
| SORTID_CPU_REQ, tmp_cpu_req, |
| SORTID_DEADLINE, tmp_time_deadline, |
| SORTID_DEPENDENCY, job_ptr->dependency, |
| SORTID_DERIVED_EC, tmp_derived_ec, |
| SORTID_EXIT_CODE, tmp_exit, |
| SORTID_EXTRA, job_ptr->extra, |
| SORTID_FEATURES, job_ptr->features, |
| SORTID_PREFER, job_ptr->prefer, |
| SORTID_FED_ACTIVE_SIBS, |
| job_ptr->fed_siblings_active_str, |
| SORTID_FED_ORIGIN, job_ptr->fed_origin_str, |
| SORTID_FED_VIABLE_SIBS, |
| job_ptr->fed_siblings_viable_str, |
| SORTID_GROUP_ID, tmp_gname, |
| SORTID_JOBID, tmp_job_id, |
| SORTID_JOBID_FORMATTED, tmp_job_id, |
| SORTID_LICENSES, job_ptr->licenses, |
| SORTID_MCS_LABEL, job_ptr->mcs_label, |
| SORTID_MEM_MIN, tmp_mem_min, |
| SORTID_MEM_PER_TRES, job_ptr->cpus_per_tres, |
| SORTID_NAME, job_ptr->name, |
| SORTID_NICE, tmp_nice, |
| SORTID_NODE_INX, job_ptr->node_inx, |
| SORTID_NODELIST, tmp_nodes, |
| SORTID_NODELIST_EXC, job_ptr->exc_nodes, |
| SORTID_NODELIST_REQ, job_ptr->req_nodes, |
| SORTID_NODELIST_SCHED, |
| job_ptr->sched_nodes, |
| SORTID_NODES, tmp_node_cnt, |
| SORTID_NODES_MAX, tmp_nodes_max, |
| SORTID_NODES_MIN, tmp_nodes_min, |
| SORTID_OVER_SUBSCRIBE, |
| job_share_string(job_ptr->shared), |
| SORTID_HET_JOB_ID, tmp_het_job_id, |
| SORTID_HET_JOB_ID_SET, tmp_het_job_id_set, |
| SORTID_HET_JOB_OFFSET, tmp_het_job_offset, |
| SORTID_PARTITION, job_ptr->partition, |
| SORTID_PREEMPT_TIME, tmp_preempt_time, |
| SORTID_PRIORITY, tmp_prio, |
| SORTID_QOS, job_ptr->qos, |
| SORTID_REASON, tmp_reason, |
| SORTID_REBOOT, tmp_reboot, |
| SORTID_REQUEUE, tmp_requeue, |
| SORTID_RESTARTS, job_ptr->restart_cnt, |
| SORTID_RESV_NAME, job_ptr->resv_name, |
| SORTID_STATE, |
| job_state_string(job_ptr->job_state), |
| SORTID_STATE_NUM, job_ptr->job_state, |
| SORTID_STD_ERR, tmp_std_err, |
| SORTID_STD_IN, tmp_std_in, |
| SORTID_STD_OUT, tmp_std_out, |
| SORTID_SWITCHES, tmp_rqswitch, |
| SORTID_THREAD_SPEC, tmp_thread_spec, |
| SORTID_TIME_ACCRUE, tmp_time_accrue, |
| SORTID_TIME_ELIGIBLE,tmp_time_elig, |
| SORTID_TIME_END, tmp_time_end, |
| SORTID_TIME_RESIZE, tmp_time_resize, |
| SORTID_TIME_RUNNING, tmp_time_run, |
| SORTID_TIME_START, tmp_time_start, |
| SORTID_TIME_SUBMIT, tmp_time_submit, |
| SORTID_TIME_SUSPEND, tmp_time_sus, |
| SORTID_TIMELIMIT, tmp_time_limit, |
| SORTID_TMP_DISK, tmp_disk, |
| SORTID_TRES_ALLOC, job_ptr->tres_alloc_str, |
| SORTID_TRES_BIND, job_ptr->tres_bind, |
| SORTID_TRES_FREQ, job_ptr->tres_freq, |
| SORTID_TRES_PER_JOB, job_ptr->tres_per_job, |
| SORTID_TRES_PER_NODE,job_ptr->tres_per_node, |
| SORTID_TRES_PER_SOCKET, |
| job_ptr->tres_per_socket, |
| SORTID_TRES_PER_TASK,job_ptr->tres_per_task, |
| SORTID_UPDATED, 1, |
| SORTID_USER_ID, tmp_uname, |
| SORTID_WCKEY, job_ptr->wckey, |
| SORTID_WORKDIR, job_ptr->work_dir, |
| -1); |
| } |
| |
| gtk_tree_store_set(treestore, iter, |
| SORTID_NETWORK, job_ptr->network, -1); |
| |
| if (check_task && |
| (job_ptr->array_task_str || |
| ((job_ptr->array_task_id != NO_VAL) || job_ptr->het_job_id))) { |
| if (gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore), |
| &step_iter, |
| iter)) |
| _update_info_task(sview_job_info_ptr, |
| GTK_TREE_MODEL(treestore), &step_iter, |
| iter, false); |
| else |
| _update_info_task(sview_job_info_ptr, |
| GTK_TREE_MODEL(treestore), NULL, |
| iter, false); |
| } else if (handle_pending && |
| (job_ptr->array_task_str || |
| (job_ptr->array_task_id != NO_VAL || |
| job_ptr->het_job_id))) { |
| if (gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore), |
| &step_iter, |
| iter)) |
| _update_info_task(sview_job_info_ptr, |
| GTK_TREE_MODEL(treestore), &step_iter, |
| iter, true); |
| else |
| _update_info_task(sview_job_info_ptr, |
| GTK_TREE_MODEL(treestore), NULL, |
| iter, true); |
| } else { |
| if (gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore), |
| &step_iter, |
| iter)) |
| _update_info_step(sview_job_info_ptr, |
| GTK_TREE_MODEL(treestore), &step_iter, |
| iter); |
| else |
| _update_info_step(sview_job_info_ptr, |
| GTK_TREE_MODEL(treestore), NULL, |
| iter); |
| } |
| |
| xfree(tmp_gname); |
| xfree(tmp_nodes); |
| |
| return; |
| } |
| |
| static int _id_from_stepstr(char *str) { |
| char *end = NULL; |
| int id = strtol(str, &end, 10); |
| /* if no digits found, it must be text */ |
| if (end == str) { |
| if (!strcasecmp(str, "TBD")) |
| id = SLURM_PENDING_STEP; |
| else if (!strcasecmp(str, "Batch")) |
| id = SLURM_BATCH_SCRIPT; |
| else if (!strcasecmp(str, "Extern")) |
| id = SLURM_EXTERN_CONT; |
| else if (!strcasecmp(str, "Interactive")) |
| id = SLURM_INTERACTIVE_STEP; |
| else |
| id = NO_VAL; |
| } |
| return id; |
| } |
| |
| static void _stepstr_from_step(job_step_info_t *step_ptr, char *dest, |
| uint32_t len) { |
| if (step_ptr->step_id.step_id == SLURM_PENDING_STEP) |
| snprintf(dest, len, "TBD"); |
| else if (step_ptr->step_id.step_id == SLURM_EXTERN_CONT) |
| snprintf(dest, len, "Extern"); |
| else if (step_ptr->step_id.step_id == SLURM_INTERACTIVE_STEP) |
| snprintf(dest, len, "Interactive"); |
| else if (step_ptr->step_id.step_id == SLURM_BATCH_SCRIPT) |
| snprintf(dest, len, "Batch"); |
| else |
| snprintf(dest, len, "%u", |
| step_ptr->step_id.step_id); |
| } |
| |
| static void _layout_step_record(GtkTreeView *treeview, |
| job_step_info_t *step_ptr, |
| int update, bool suspended) |
| { |
| char *uname; |
| char *tmp_nodes; |
| char tmp_char[100], tmp_str[50], tmp_time[50]; |
| GtkTreeIter iter; |
| uint32_t state; |
| GtkTreeStore *treestore = |
| GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); |
| |
| if (!treestore) |
| return; |
| |
| convert_num_unit((float)step_ptr->num_cpus, tmp_char, sizeof(tmp_char), |
| UNIT_NONE, NO_VAL, working_sview_config.convert_flags); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CPUS), |
| tmp_char); |
| |
| uname = uid_to_string_cached((uid_t)step_ptr->user_id); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_USER_ID), uname); |
| |
| if (step_ptr->array_job_id) { |
| snprintf(tmp_char, sizeof(tmp_char), "%u_%u.%u (%u.%u)", |
| step_ptr->array_job_id, step_ptr->array_task_id, |
| step_ptr->step_id.step_id, |
| step_ptr->step_id.job_id, step_ptr->step_id.step_id); |
| // } else if (step_ptr->het_job_id) { |
| // snprintf(tmp_char, sizeof(tmp_char), "%u+%u.%u (%u.%u)", |
| // step_ptr->het_job_id, step_ptr->het_job_offset, |
| // step_ptr->step_id.step_id, |
| // step_ptr->step_id.job_id, step_ptr->step_id.step_id); |
| } else { |
| _stepstr_from_step(step_ptr, tmp_str, sizeof(tmp_str)); |
| snprintf(tmp_char, sizeof(tmp_char), "%u.%s", |
| step_ptr->step_id.job_id, tmp_str); |
| } |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_JOBID), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_CPUS_PER_TRES), |
| step_ptr->cpus_per_tres); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_MEM_PER_TRES), |
| step_ptr->mem_per_tres); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_BIND), |
| step_ptr->tres_bind); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_FREQ), |
| step_ptr->tres_freq); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_PER_JOB), |
| step_ptr->tres_per_step); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_PER_NODE), |
| step_ptr->tres_per_node); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_PER_SOCKET), |
| step_ptr->tres_per_socket); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_PER_TASK), |
| step_ptr->tres_per_task); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NAME), |
| step_ptr->name); |
| |
| |
| if (suspended) |
| state = JOB_SUSPENDED; |
| else |
| state = step_ptr->state; |
| |
| if (!step_ptr->nodes |
| || !xstrcasecmp(step_ptr->nodes, "waiting...")) { |
| sprintf(tmp_time,"00:00:00"); |
| tmp_nodes = xstrdup("waiting..."); |
| state = JOB_PENDING; |
| } else { |
| secs2time_str(step_ptr->run_time, tmp_time, sizeof(tmp_time)); |
| tmp_nodes = slurm_sort_node_list_str(step_ptr->nodes); |
| convert_num_unit((float)_nodes_in_list(tmp_nodes), |
| tmp_char, sizeof(tmp_char), UNIT_NONE, |
| NO_VAL, |
| working_sview_config.convert_flags); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODES), |
| tmp_char); |
| } |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_NODELIST), |
| tmp_nodes); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_PARTITION), |
| step_ptr->partition); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_STATE), |
| job_state_string(state)); |
| |
| if (step_ptr->time_limit == NO_VAL) |
| sprintf(tmp_char, "Partition Limit"); |
| else if (step_ptr->time_limit == INFINITE) |
| sprintf(tmp_char, "Infinite"); |
| else |
| secs2time_str((step_ptr->time_limit * 60), |
| tmp_char, sizeof(tmp_char)); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIMELIMIT), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TIME_RUNNING), |
| tmp_time); |
| |
| convert_num_unit((float)step_ptr->num_tasks, tmp_char, sizeof(tmp_char), |
| UNIT_NONE, NO_VAL, working_sview_config.convert_flags); |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TASKS), |
| tmp_char); |
| |
| add_display_treestore_line(update, treestore, &iter, |
| find_col_name(display_data_job, |
| SORTID_TRES_ALLOC), |
| step_ptr->tres_fmt_alloc_str); |
| |
| xfree(tmp_nodes); |
| } |
| |
| static void _update_step_record(job_step_info_t *step_ptr, |
| GtkTreeStore *treestore, |
| GtkTreeIter *iter, bool suspended) |
| { |
| char *tmp_uname; |
| char *tmp_nodes; |
| char tmp_cpu_min[40], tmp_time_run[40], tmp_time_limit[40]; |
| char tmp_node_cnt[40], tmp_time_start[256], tmp_task_cnt[40]; |
| char tmp_step_id[40], tmp_job_id[400]; |
| char tmp_fmt_stepid[40]; |
| uint32_t state; |
| int color_inx = step_ptr->step_id.step_id % sview_colors_cnt; |
| |
| convert_num_unit((float)step_ptr->num_cpus, tmp_cpu_min, |
| sizeof(tmp_cpu_min), UNIT_NONE, NO_VAL, |
| working_sview_config.convert_flags); |
| |
| if (suspended) |
| state = JOB_SUSPENDED; |
| else |
| state = step_ptr->state; |
| |
| if (!step_ptr->nodes || |
| !xstrcasecmp(step_ptr->nodes,"waiting...")) { |
| sprintf(tmp_time_run, "00:00:00"); |
| tmp_nodes = xstrdup("waiting..."); |
| tmp_node_cnt[0] = '\0'; |
| state = JOB_PENDING; |
| } else { |
| secs2time_str(step_ptr->run_time, |
| tmp_time_run, sizeof(tmp_time_run)); |
| tmp_nodes = slurm_sort_node_list_str(step_ptr->nodes); |
| convert_num_unit((float)_nodes_in_list(tmp_nodes), |
| tmp_node_cnt, sizeof(tmp_node_cnt), |
| UNIT_NONE, NO_VAL, |
| working_sview_config.convert_flags); |
| } |
| |
| convert_num_unit((float)step_ptr->num_tasks, tmp_task_cnt, |
| sizeof(tmp_task_cnt), UNIT_NONE, NO_VAL, |
| working_sview_config.convert_flags); |
| |
| if ((step_ptr->time_limit == NO_VAL) || |
| (step_ptr->time_limit == INFINITE)) { |
| sprintf(tmp_time_limit, "Job Limit"); |
| } else { |
| secs2time_str((step_ptr->time_limit * 60), |
| tmp_time_limit, sizeof(tmp_time_limit)); |
| } |
| |
| slurm_make_time_str((time_t *)&step_ptr->start_time, tmp_time_start, |
| sizeof(tmp_time_start)); |
| |
| _stepstr_from_step(step_ptr, tmp_fmt_stepid, sizeof(tmp_fmt_stepid)); |
| snprintf(tmp_step_id, sizeof(tmp_step_id), "%u", |
| step_ptr->step_id.step_id); |
| |
| if (step_ptr->array_job_id) { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%u_%u.%u (%u.%u)", |
| step_ptr->array_job_id, step_ptr->array_task_id, |
| step_ptr->step_id.step_id, |
| step_ptr->step_id.job_id, step_ptr->step_id.step_id); |
| // } else if (step_ptr->het_job_id) { |
| // snprintf(tmp_job_id, sizeof(tmp_job_id), "%u+%u.%u (%u.%u)", |
| // step_ptr->het_job_id, step_ptr->het_job_offset, |
| // step_ptr->step_id.step_id, |
| // step_ptr->step_id.job_id, step_ptr->step_id.step_id); |
| } else { |
| snprintf(tmp_job_id, sizeof(tmp_job_id), "%u.%s", |
| step_ptr->step_id.job_id, tmp_fmt_stepid); |
| } |
| |
| tmp_uname = uid_to_string_cached((uid_t)step_ptr->user_id); |
| |
| gtk_tree_store_set(treestore, iter, |
| SORTID_ALLOC, 0, |
| SORTID_COLOR, sview_colors[color_inx], |
| SORTID_COLOR_INX, color_inx, |
| SORTID_CPUS, tmp_cpu_min, |
| SORTID_CPUS_PER_TRES, step_ptr->cpus_per_tres, |
| SORTID_JOBID, tmp_fmt_stepid, |
| SORTID_JOBID_FORMATTED, tmp_job_id, |
| SORTID_MEM_PER_TRES, step_ptr->mem_per_tres, |
| SORTID_NAME, step_ptr->name, |
| SORTID_NODE_INX, step_ptr->node_inx, |
| SORTID_NODELIST, tmp_nodes, |
| SORTID_NODES, tmp_node_cnt, |
| SORTID_PARTITION, step_ptr->partition, |
| SORTID_STATE, job_state_string(state), |
| SORTID_TASKS, tmp_task_cnt, |
| SORTID_TIME_RUNNING, tmp_time_run, |
| SORTID_TIME_START, tmp_time_start, |
| SORTID_TIMELIMIT, tmp_time_limit, |
| SORTID_TRES_ALLOC, step_ptr->tres_fmt_alloc_str, |
| SORTID_TRES_BIND, step_ptr->tres_bind, |
| SORTID_TRES_FREQ, step_ptr->tres_freq, |
| SORTID_TRES_PER_JOB, step_ptr->tres_per_step, |
| SORTID_TRES_PER_NODE, step_ptr->tres_per_node, |
| SORTID_TRES_PER_SOCKET, step_ptr->tres_per_socket, |
| SORTID_TRES_PER_TASK, step_ptr->tres_per_task, |
| SORTID_UPDATED, 1, |
| SORTID_USER_ID, tmp_uname, |
| -1); |
| |
| xfree(tmp_nodes); |
| |
| return; |
| } |
| |
| static void _append_job_record(sview_job_info_t *sview_job_info_ptr, |
| GtkTreeStore *treestore) |
| { |
| gtk_tree_store_append(treestore, &sview_job_info_ptr->iter_ptr, NULL); |
| gtk_tree_store_set(treestore, &sview_job_info_ptr->iter_ptr, SORTID_POS, |
| sview_job_info_ptr->pos, -1); |
| _update_job_record(sview_job_info_ptr, treestore, NULL, true, false); |
| } |
| |
| static void _append_task_record(sview_job_info_t *sview_job_info_ptr, |
| GtkTreeStore *treestore, GtkTreeIter *iter, |
| bool handle_pending) |
| { |
| GtkTreeIter task_iter; |
| |
| gtk_tree_store_append(treestore, &task_iter, iter); |
| gtk_tree_store_set(treestore, &task_iter, SORTID_POS, |
| sview_job_info_ptr->pos, -1); |
| _update_job_record(sview_job_info_ptr, treestore, &task_iter, false, |
| handle_pending); |
| } |
| |
| |
| static void _append_step_record(job_step_info_t *step_ptr, |
| GtkTreeStore *treestore, GtkTreeIter *iter, |
| int jobid, bool suspended) |
| { |
| GtkTreeIter step_iter; |
| |
| gtk_tree_store_append(treestore, &step_iter, iter); |
| gtk_tree_store_set(treestore, &step_iter, SORTID_POS, jobid, -1); |
| _update_step_record(step_ptr, treestore, &step_iter, suspended); |
| } |
| |
| static void _handle_task_check(sview_job_info_t *task_ptr, |
| GtkTreeModel *model, |
| GtkTreeIter **task_iter, |
| GtkTreeIter *first_task_iter, |
| GtkTreeIter *iter, |
| bool handle_pending) |
| { |
| /* get the iter, or find out the list is empty goto add */ |
| if (!*task_iter) |
| goto adding; |
| else |
| memcpy(*task_iter, first_task_iter, sizeof(GtkTreeIter)); |
| |
| while (1) { |
| char *tmp_taskid, *use_id; |
| /* search for the jobid and check to see if |
| * it is in the list */ |
| gtk_tree_model_get(model, *task_iter, SORTID_JOBID, |
| &tmp_taskid, -1); |
| |
| if (handle_pending) |
| use_id = task_ptr->task_pending_hl_str; |
| else |
| use_id = task_ptr->job_id_str; |
| |
| if (tmp_taskid && use_id && !xstrcmp(tmp_taskid, use_id)) { |
| /* update with new info */ |
| _update_job_record(task_ptr, |
| GTK_TREE_STORE(model), |
| *task_iter, false, handle_pending); |
| g_free(tmp_taskid); |
| goto found; |
| } |
| g_free(tmp_taskid); |
| |
| if (!gtk_tree_model_iter_next(model, *task_iter)) { |
| *task_iter = NULL; |
| break; |
| } |
| } |
| adding: |
| _append_task_record(task_ptr, GTK_TREE_STORE(model), |
| iter, handle_pending); |
| found: |
| return; |
| |
| |
| } |
| |
| |
| static void _update_info_task(sview_job_info_t *sview_job_info_ptr, |
| GtkTreeModel *model, |
| GtkTreeIter *task_iter, |
| GtkTreeIter *iter, bool handle_pending) |
| { |
| int i; |
| GtkTreeIter first_task_iter; |
| int set = 0; |
| list_itr_t *itr = NULL; |
| sview_job_info_t *task_ptr = NULL; |
| |
| memset(&first_task_iter, 0, sizeof(GtkTreeIter)); |
| |
| /* make sure all the tasks are still here */ |
| if (task_iter) { |
| first_task_iter = *task_iter; |
| while (1) { |
| gtk_tree_store_set(GTK_TREE_STORE(model), task_iter, |
| SORTID_UPDATED, 0, -1); |
| if (!gtk_tree_model_iter_next(model, task_iter)) { |
| break; |
| } |
| } |
| memcpy(task_iter, &first_task_iter, sizeof(GtkTreeIter)); |
| set = 1; |
| } |
| if (handle_pending) |
| itr = list_iterator_create( |
| sview_job_info_ptr->task_pending_list); |
| else { |
| /* First handle the pending list if one exists. This |
| will make a dummy job record that holds all the |
| pending jobs. |
| */ |
| if (sview_job_info_ptr->task_pending_list && |
| list_count(sview_job_info_ptr->task_pending_list)) |
| _handle_task_check(sview_job_info_ptr, model, |
| &task_iter, &first_task_iter, |
| iter, true); |
| itr = list_iterator_create(sview_job_info_ptr->task_list); |
| } |
| while ((task_ptr = list_next(itr))) |
| _handle_task_check(task_ptr, model, &task_iter, |
| &first_task_iter, iter, false); |
| list_iterator_destroy(itr); |
| |
| if (set) { |
| task_iter = &first_task_iter; |
| /* clear all tasks that aren't active */ |
| while (1) { |
| gtk_tree_model_get(model, task_iter, |
| SORTID_UPDATED, &i, -1); |
| if (!i) { |
| if (!gtk_tree_store_remove( |
| GTK_TREE_STORE(model), |
| task_iter)) |
| break; |
| else |
| continue; |
| } |
| if (!gtk_tree_model_iter_next(model, task_iter)) { |
| break; |
| } |
| } |
| } |
| return; |
| } |
| |
| static void _update_info_step(sview_job_info_t *sview_job_info_ptr, |
| GtkTreeModel *model, |
| GtkTreeIter *step_iter, |
| GtkTreeIter *iter) |
| { |
| int stepid = 0; |
| int i; |
| GtkTreeIter first_step_iter; |
| int set = 0; |
| list_itr_t *itr = NULL; |
| job_step_info_t *step_ptr = NULL; |
| |
| memset(&first_step_iter, 0, sizeof(GtkTreeIter)); |
| |
| /* make sure all the steps are still here */ |
| if (step_iter) { |
| first_step_iter = *step_iter; |
| while (1) { |
| gtk_tree_store_set(GTK_TREE_STORE(model), step_iter, |
| SORTID_UPDATED, 0, -1); |
| if (!gtk_tree_model_iter_next(model, step_iter)) { |
| break; |
| } |
| } |
| memcpy(step_iter, &first_step_iter, sizeof(GtkTreeIter)); |
| set = 1; |
| } |
| itr = list_iterator_create(sview_job_info_ptr->step_list); |
| while ((step_ptr = list_next(itr))) { |
| /* get the iter, or find out the list is empty goto add */ |
| if (!step_iter) { |
| goto adding; |
| } else { |
| memcpy(step_iter, &first_step_iter, |
| sizeof(GtkTreeIter)); |
| } |
| while (1) { |
| char *tmp_stepid; |
| /* search for the jobid and check to see if |
| * it is in the list */ |
| gtk_tree_model_get(model, step_iter, SORTID_JOBID, |
| &tmp_stepid, -1); |
| stepid = atoi(tmp_stepid); |
| g_free(tmp_stepid); |
| if (stepid == (int)step_ptr->step_id.step_id) { |
| /* update with new info */ |
| _update_step_record( |
| step_ptr, GTK_TREE_STORE(model), |
| step_iter, IS_JOB_SUSPENDED( |
| sview_job_info_ptr->job_ptr)); |
| goto found; |
| } |
| |
| if (!gtk_tree_model_iter_next(model, step_iter)) { |
| step_iter = NULL; |
| break; |
| } |
| } |
| adding: |
| _append_step_record(step_ptr, GTK_TREE_STORE(model), |
| iter, sview_job_info_ptr->job_ptr->job_id, |
| IS_JOB_SUSPENDED( |
| sview_job_info_ptr->job_ptr)); |
| found: |
| ; |
| } |
| list_iterator_destroy(itr); |
| |
| if (set) { |
| step_iter = &first_step_iter; |
| /* clear all steps that aren't active */ |
| while (1) { |
| gtk_tree_model_get(model, step_iter, |
| SORTID_UPDATED, &i, -1); |
| if (!i) { |
| if (!gtk_tree_store_remove( |
| GTK_TREE_STORE(model), |
| step_iter)) |
| break; |
| else |
| continue; |
| } |
| if (!gtk_tree_model_iter_next(model, step_iter)) { |
| break; |
| } |
| } |
| } |
| return; |
| } |
| |
| static void _update_info_job(list_t *info_list, GtkTreeView *tree_view) |
| { |
| GtkTreeModel *model = gtk_tree_view_get_model(tree_view); |
| int jobid = 0; |
| job_info_t *job_ptr = NULL; |
| list_itr_t *itr = NULL; |
| sview_job_info_t *sview_job_info = NULL; |
| |
| set_for_update(model, SORTID_UPDATED); |
| |
| itr = list_iterator_create(info_list); |
| while ((sview_job_info = list_next(itr))) { |
| job_ptr = sview_job_info->job_ptr; |
| |
| /* This means the tree_store changed (added new column |
| * or something). */ |
| if (last_model != model) |
| sview_job_info->iter_set = false; |
| |
| if (sview_job_info->iter_set) { |
| char *tmp_jobid = NULL, *offset = NULL; |
| gtk_tree_model_get(model, &sview_job_info->iter_ptr, |
| SORTID_JOBID, &tmp_jobid, -1); |
| if (!tmp_jobid) |
| continue; |
| |
| offset = strchr(tmp_jobid, '('); |
| if (offset) |
| offset++; |
| else |
| offset = tmp_jobid; |
| jobid = atoi(offset); |
| g_free(tmp_jobid); |
| |
| if ((jobid != job_ptr->job_id) |
| && (jobid != job_ptr->array_job_id) && |
| (jobid != job_ptr->het_job_id)) { |
| /* Bad pointer */ |
| sview_job_info->iter_set = false; |
| } |
| } |
| if (sview_job_info->iter_set) |
| _update_job_record(sview_job_info, |
| GTK_TREE_STORE(model), NULL, true, |
| false); |
| else { |
| _append_job_record(sview_job_info, |
| GTK_TREE_STORE(model)); |
| sview_job_info->iter_set = true; |
| } |
| } |
| list_iterator_destroy(itr); |
| |
| /* remove all old jobs */ |
| remove_old(model, SORTID_UPDATED); |
| last_model = model; |
| return; |
| } |
| |
| static int _sview_job_sort_aval_dec(void *s1, void *s2) |
| { |
| sview_job_info_t* rec_a = *(sview_job_info_t **)s1; |
| sview_job_info_t* rec_b = *(sview_job_info_t **)s2; |
| int size_a; |
| int size_b; |
| |
| size_a = rec_a->node_cnt; |
| size_b = rec_b->node_cnt; |
| |
| if (size_a < size_b) |
| return -1; |
| else if (size_a > size_b) |
| return 1; |
| |
| if (rec_a->nodes && rec_b->nodes) { |
| size_a = xstrcmp(rec_a->nodes, rec_b->nodes); |
| if (size_a < 0) |
| return -1; |
| else if (size_a > 0) |
| return 1; |
| } |
| return 0; |
| } |
| |
| static int _task_array_match(void *x, void *key) |
| { |
| sview_job_info_t *sview_job_info_ptr = (sview_job_info_t *) x; |
| job_info_t *job_ptr = (job_info_t *) key; |
| |
| if (sview_job_info_ptr->job_ptr->array_job_id == job_ptr->array_job_id) |
| return 1; |
| |
| return 0; |
| } |
| |
| static int _het_job_id_match(void *x, void *key) |
| { |
| sview_job_info_t *sview_job_info_ptr = (sview_job_info_t *) x; |
| job_info_t *job_ptr = (job_info_t *) key; |
| |
| if (sview_job_info_ptr->job_ptr->het_job_id == job_ptr->het_job_id) |
| return 1; |
| |
| return 0; |
| } |
| |
| static list_t *_create_job_info_list(job_info_msg_t *job_info_ptr, |
| job_step_info_response_msg_t *step_info_ptr, |
| int want_odd_states) |
| { |
| static list_t *info_list = NULL; |
| static list_t *odd_info_list = NULL; |
| list_t *last_list = NULL; |
| list_itr_t *last_list_itr = NULL; |
| static job_info_msg_t *last_job_info_ptr = NULL; |
| static job_step_info_response_msg_t *last_step_info_ptr = NULL; |
| int i = 0, j = 0; |
| sview_job_info_t *sview_job_info_ptr = NULL; |
| job_info_t *job_ptr = NULL; |
| job_step_info_t *step_ptr = NULL; |
| |
| if (info_list && (job_info_ptr == last_job_info_ptr) |
| && (step_info_ptr == last_step_info_ptr)) |
| goto update_color; |
| |
| last_job_info_ptr = job_info_ptr; |
| last_step_info_ptr = step_info_ptr; |
| |
| if (info_list) { |
| list_flush(info_list); |
| last_list = odd_info_list; |
| odd_info_list = list_create(_job_info_list_del); |
| } else { |
| info_list = list_create(NULL); |
| odd_info_list = list_create(_job_info_list_del); |
| } |
| if (last_list) |
| last_list_itr = list_iterator_create(last_list); |
| for (i=0; i<job_info_ptr->record_count; i++) { |
| bool added_task = false; |
| |
| job_ptr = &(job_info_ptr->job_array[i]); |
| if (job_ptr->job_id == 0) |
| continue; |
| |
| sview_job_info_ptr = NULL; |
| |
| if (last_list_itr) { |
| while ((sview_job_info_ptr = |
| list_next(last_list_itr))) { |
| if (sview_job_info_ptr->job_id == |
| job_ptr->job_id) { |
| list_remove(last_list_itr); |
| _job_info_free(sview_job_info_ptr); |
| break; |
| } |
| } |
| list_iterator_reset(last_list_itr); |
| } |
| |
| if (!sview_job_info_ptr) |
| sview_job_info_ptr = xmalloc(sizeof(sview_job_info_t)); |
| |
| sview_job_info_ptr->job_ptr = job_ptr; |
| sview_job_info_ptr->job_id = job_ptr->job_id; |
| |
| if (job_ptr->array_task_str || |
| (job_ptr->array_task_id != NO_VAL)) { |
| char task_str[64]; |
| sview_job_info_t *first_job_info_ptr = |
| list_find_first(info_list, |
| _task_array_match, job_ptr); |
| if (job_ptr->array_task_str) { |
| snprintf(task_str, sizeof(task_str), "[%s]", |
| job_ptr->array_task_str); |
| } else { |
| snprintf(task_str, sizeof(task_str), "%u", |
| job_ptr->array_task_id); |
| } |
| |
| if (!first_job_info_ptr) { |
| sview_job_info_ptr->task_list = |
| list_create(NULL); |
| sview_job_info_ptr->task_hl = |
| hostlist_create(NULL); |
| first_job_info_ptr = sview_job_info_ptr; |
| } else if (!IS_JOB_COMPLETED(job_ptr)) |
| added_task = true; |
| |
| hostlist_push_host(first_job_info_ptr->task_hl, |
| task_str); |
| |
| if (IS_JOB_PENDING(job_ptr)) { |
| if (!first_job_info_ptr->task_pending_list) |
| first_job_info_ptr->task_pending_list = |
| list_create(NULL); |
| if (!first_job_info_ptr->task_pending_hl) |
| first_job_info_ptr->task_pending_hl = |
| hostlist_create(NULL); |
| hostlist_push_host( |
| first_job_info_ptr->task_pending_hl, |
| task_str); |
| list_append(first_job_info_ptr-> |
| task_pending_list, |
| sview_job_info_ptr); |
| } else if (!IS_JOB_COMPLETED(job_ptr)) |
| list_append(first_job_info_ptr->task_list, |
| sview_job_info_ptr); |
| if (job_ptr->array_task_str) { |
| sview_job_info_ptr->job_id_str = |
| xstrdup_printf("%u_[%s] (%u)", |
| job_ptr->array_job_id, |
| job_ptr->array_task_str, |
| job_ptr->job_id); |
| } else { |
| sview_job_info_ptr->job_id_str = |
| xstrdup_printf("%u_%u (%u)", |
| job_ptr->array_job_id, |
| job_ptr->array_task_id, |
| job_ptr->job_id); |
| } |
| } else if (job_ptr->het_job_id) { |
| char comp_str[64]; |
| snprintf(comp_str, sizeof(comp_str), "%u", |
| job_ptr->het_job_offset); |
| sview_job_info_t *first_job_info_ptr = |
| list_find_first(info_list, |
| _het_job_id_match, job_ptr); |
| if (!first_job_info_ptr) { |
| sview_job_info_ptr->task_list = |
| list_create(NULL); |
| sview_job_info_ptr->task_hl = |
| hostlist_create(NULL); |
| first_job_info_ptr = sview_job_info_ptr; |
| } else if (!IS_JOB_COMPLETED(job_ptr)) |
| added_task = true; |
| |
| hostlist_push_host(first_job_info_ptr->task_hl, |
| comp_str); |
| if (!IS_JOB_COMPLETED(job_ptr)) |
| list_append(first_job_info_ptr->task_list, |
| sview_job_info_ptr); |
| sview_job_info_ptr->job_id_str = |
| xstrdup_printf("%u+%u (%u)", |
| job_ptr->het_job_id, |
| job_ptr->het_job_offset, |
| job_ptr->job_id); |
| } else |
| sview_job_info_ptr->job_id_str = |
| xstrdup_printf("%u", job_ptr->job_id); |
| |
| sview_job_info_ptr->step_list = list_create(NULL); |
| sview_job_info_ptr->pos = i; |
| sview_job_info_ptr->node_cnt = 0; |
| sview_job_info_ptr->color_inx = |
| job_ptr->job_id % sview_colors_cnt; |
| sview_job_info_ptr->nodes = xstrdup(job_ptr->nodes); |
| sview_job_info_ptr->node_cnt = job_ptr->num_nodes; |
| |
| for (j = 0; j < step_info_ptr->job_step_count; j++) { |
| step_ptr = &(step_info_ptr->job_steps[j]); |
| if ((step_ptr->step_id.job_id == job_ptr->job_id) && |
| (step_ptr->state == JOB_RUNNING)) { |
| list_append(sview_job_info_ptr->step_list, |
| step_ptr); |
| } |
| } |
| if (!added_task) |
| list_append(odd_info_list, sview_job_info_ptr); |
| |
| if (!IS_JOB_PENDING(job_ptr) && |
| !IS_JOB_RUNNING(job_ptr) && |
| !IS_JOB_SUSPENDED(job_ptr) && |
| !IS_JOB_COMPLETING(job_ptr)) { |
| continue; |
| } |
| |
| if (!added_task) |
| list_append(info_list, sview_job_info_ptr); |
| } |
| |
| list_sort(info_list, (ListCmpF)_sview_job_sort_aval_dec); |
| |
| list_sort(odd_info_list, (ListCmpF)_sview_job_sort_aval_dec); |
| |
| if (last_list) { |
| list_iterator_destroy(last_list_itr); |
| FREE_NULL_LIST(last_list); |
| } |
| |
| update_color: |
| |
| if (want_odd_states) |
| return odd_info_list; |
| else |
| return info_list; |
| |
| } |
| |
| void _display_info_job(list_t *info_list, popup_info_t *popup_win) |
| { |
| job_step_info_t *step_ptr; |
| specific_info_t *spec_info = popup_win->spec_info; |
| list_itr_t *itr = NULL, *itr2 = NULL; |
| sview_job_info_t *sview_job_info = NULL, *sview_job_info2 = NULL; |
| int found = 0; |
| GtkTreeView *treeview = NULL; |
| int update = 0; |
| int j, k; |
| |
| if (spec_info->search_info->int_data == NO_VAL) { |
| /* info = xstrdup("No pointer given!"); */ |
| goto finished; |
| } |
| |
| need_refresh: |
| if (!spec_info->display_widget) { |
| treeview = create_treeview_2cols_attach_to_table( |
| popup_win->table); |
| spec_info->display_widget = |
| g_object_ref(GTK_WIDGET(treeview)); |
| } else { |
| treeview = GTK_TREE_VIEW(spec_info->display_widget); |
| update = 1; |
| } |
| |
| itr = list_iterator_create(info_list); |
| while ((sview_job_info = list_next(itr))) { |
| if (sview_job_info->job_ptr->job_id == |
| spec_info->search_info->int_data) |
| break; |
| if (sview_job_info->task_list) { |
| itr2 = list_iterator_create(sview_job_info->task_list); |
| while ((sview_job_info2 = list_next(itr2))) { |
| if (sview_job_info2->job_ptr->job_id == |
| spec_info->search_info->int_data) |
| break; |
| } |
| list_iterator_destroy(itr2); |
| if (sview_job_info2) { |
| sview_job_info = sview_job_info2; |
| break; |
| } |
| } |
| if (sview_job_info->task_pending_list) { |
| itr2 = list_iterator_create( |
| sview_job_info->task_pending_list); |
| while ((sview_job_info2 = list_next(itr2))) { |
| if (sview_job_info2->job_ptr->job_id == |
| spec_info->search_info->int_data) |
| break; |
| } |
| list_iterator_destroy(itr2); |
| if (sview_job_info2) { |
| sview_job_info = sview_job_info2; |
| break; |
| } |
| } |
| } |
| list_iterator_destroy(itr); |
| |
| if (!sview_job_info) { |
| /* not found */ |
| } else if (spec_info->search_info->int_data2 == NO_VAL) { |
| int top_node_inx = 0; |
| int array_size = SVIEW_MAX_NODE_SPACE; |
| int *color_inx = xmalloc(sizeof(int) * array_size); |
| bool *color_set_flag = xmalloc(sizeof(bool) * array_size); |
| j = 0; |
| while (sview_job_info->job_ptr->node_inx[j] >= 0) { |
| top_node_inx = MAX(top_node_inx, |
| sview_job_info->job_ptr-> |
| node_inx[j+1]); |
| if (top_node_inx > SVIEW_MAX_NODE_SPACE) |
| fatal("Expand SVIEW_MAX_NODE_SPACE in sview"); |
| for (k = sview_job_info->job_ptr->node_inx[j]; |
| k <= sview_job_info->job_ptr->node_inx[j+1]; |
| k++) { |
| color_set_flag[k] = true; |
| color_inx[k] = sview_job_info-> |
| color_inx; |
| } |
| j += 2; |
| } |
| change_grid_color_array(popup_win->grid_button_list, |
| top_node_inx+1, color_inx, |
| color_set_flag, true, 0); |
| xfree(color_inx); |
| xfree(color_set_flag); |
| _layout_job_record(treeview, sview_job_info, update); |
| found = 1; |
| } else { |
| int top_node_inx = 0; |
| int array_size = SVIEW_MAX_NODE_SPACE; |
| int *color_inx = xmalloc(sizeof(int) * array_size); |
| bool *color_set_flag = xmalloc(sizeof(bool) * array_size); |
| itr = list_iterator_create(sview_job_info->step_list); |
| while ((step_ptr = list_next(itr))) { |
| if (step_ptr->step_id.step_id == |
| spec_info->search_info->int_data2) { |
| j = 0; |
| while (step_ptr->node_inx[j] >= 0) { |
| top_node_inx = MAX(top_node_inx, |
| step_ptr-> |
| node_inx[j+1]); |
| if (top_node_inx > SVIEW_MAX_NODE_SPACE) |
| fatal("Expand " |
| "SVIEW_MAX_NODE_SPACE " |
| "in sview"); |
| for (k = step_ptr->node_inx[j]; |
| k <= step_ptr->node_inx[j+1]; |
| k++) { |
| color_set_flag[k] = true; |
| color_inx[k] = step_ptr->step_id.step_id |
| % sview_colors_cnt; |
| } |
| j += 2; |
| } |
| change_grid_color_array( |
| popup_win->grid_button_list, |
| top_node_inx+1, color_inx, |
| color_set_flag, false, 0); |
| xfree(color_inx); |
| xfree(color_set_flag); |
| |
| _layout_step_record( |
| treeview, step_ptr, update, |
| IS_JOB_SUSPENDED( |
| sview_job_info->job_ptr)); |
| found = 1; |
| break; |
| } |
| } |
| list_iterator_destroy(itr); |
| xfree(color_inx); |
| xfree(color_set_flag); |
| } |
| post_setup_popup_grid_list(popup_win); |
| |
| if (!found) { |
| if (!popup_win->not_found) { |
| char *temp = "JOB ALREADY FINISHED OR NOT FOUND\n"; |
| GtkTreeIter iter; |
| GtkTreeModel *model = NULL; |
| |
| /* only time this will be run so no update */ |
| model = gtk_tree_view_get_model(treeview); |
| add_display_treestore_line(0, |
| GTK_TREE_STORE(model), |
| &iter, |
| temp, ""); |
| if (spec_info->search_info->int_data2 != NO_VAL) |
| add_display_treestore_line( |
| 1, |
| GTK_TREE_STORE(model), |
| &iter, |
| find_col_name(display_data_job, |
| SORTID_STATE), |
| job_state_string(JOB_COMPLETE)); |
| } |
| popup_win->not_found = true; |
| } else { |
| if (popup_win->not_found) { |
| popup_win->not_found = false; |
| gtk_widget_destroy(spec_info->display_widget); |
| |
| goto need_refresh; |
| } |
| } |
| gtk_widget_show_all(spec_info->display_widget); |
| |
| finished: |
| return; |
| } |
| |
| extern void refresh_job(GtkAction *action, gpointer user_data) |
| { |
| popup_info_t *popup_win = (popup_info_t *)user_data; |
| xassert(popup_win); |
| xassert(popup_win->spec_info); |
| xassert(popup_win->spec_info->title); |
| popup_win->force_refresh = 1; |
| specific_info_job(popup_win); |
| } |
| |
| extern int get_new_info_job(job_info_msg_t **info_ptr, |
| int force) |
| { |
| job_info_msg_t *new_job_ptr = NULL; |
| uint16_t show_flags = 0; |
| int error_code = SLURM_NO_CHANGE_IN_DATA, i; |
| time_t now = time(NULL); |
| static time_t last; |
| static bool changed = 0; |
| static uint16_t last_flags = 0; |
| slurm_job_info_t *job_ptr; |
| char *local_cluster; |
| |
| if (g_job_info_ptr && !force |
| && ((now - last) < working_sview_config.refresh_delay)) { |
| if (*info_ptr != g_job_info_ptr) |
| error_code = SLURM_SUCCESS; |
| *info_ptr = g_job_info_ptr; |
| if (changed) |
| error_code = SLURM_SUCCESS; |
| goto end_it; |
| } |
| last = now; |
| |
| if (cluster_flags & CLUSTER_FLAG_FED) |
| show_flags |= SHOW_FEDERATION; |
| if (working_sview_config.show_hidden) |
| show_flags |= SHOW_ALL; |
| if (g_job_info_ptr) { |
| if (show_flags != last_flags) |
| g_job_info_ptr->last_update = 0; |
| error_code = slurm_load_jobs(g_job_info_ptr->last_update, |
| &new_job_ptr, show_flags); |
| if (error_code == SLURM_SUCCESS) { |
| slurm_free_job_info_msg(g_job_info_ptr); |
| changed = 1; |
| } else if (errno == SLURM_NO_CHANGE_IN_DATA) { |
| error_code = SLURM_NO_CHANGE_IN_DATA; |
| new_job_ptr = g_job_info_ptr; |
| changed = 0; |
| } |
| } else { |
| new_job_ptr = NULL; |
| error_code = slurm_load_jobs((time_t) NULL, &new_job_ptr, |
| show_flags); |
| changed = 1; |
| } |
| |
| /* If job not local, clear node_inx to avoid setting node colors */ |
| if (working_cluster_rec && working_cluster_rec->name) |
| local_cluster = xstrdup(working_cluster_rec->name); |
| else |
| local_cluster = xstrdup(slurm_conf.cluster_name); |
| if (error_code == SLURM_SUCCESS) { |
| for (i = 0, job_ptr = new_job_ptr->job_array; |
| i < new_job_ptr->record_count; i++, job_ptr++) { |
| if (job_ptr->node_inx && job_ptr->cluster && |
| xstrcmp(job_ptr->cluster, local_cluster)) { |
| job_ptr->node_inx[0] = -1; |
| } |
| } |
| } |
| xfree(local_cluster); |
| |
| last_flags = show_flags; |
| g_job_info_ptr = new_job_ptr; |
| |
| if (g_job_info_ptr && (*info_ptr != g_job_info_ptr)) |
| error_code = SLURM_SUCCESS; |
| |
| *info_ptr = g_job_info_ptr; |
| end_it: |
| return error_code; |
| } |
| |
| extern int get_new_info_job_step(job_step_info_response_msg_t **info_ptr, |
| int force) |
| { |
| job_step_info_response_msg_t *new_step_ptr = NULL; |
| uint16_t show_flags = 0; |
| int error_code = SLURM_NO_CHANGE_IN_DATA; |
| time_t now = time(NULL); |
| static time_t last; |
| static bool changed = 0; |
| |
| if (g_step_info_ptr && !force |
| && ((now - last) < working_sview_config.refresh_delay)) { |
| if (*info_ptr != g_step_info_ptr) |
| error_code = SLURM_SUCCESS; |
| *info_ptr = g_step_info_ptr; |
| if (changed) |
| error_code = SLURM_SUCCESS; |
| goto end_it; |
| } |
| last = now; |
| |
| /* This needs to always be like this even if you are only |
| looking for non-hidden jobs or you will get an error below. |
| */ |
| show_flags |= SHOW_ALL; |
| if (g_step_info_ptr) { |
| /* Use a last_update time of NULL so that we can get an updated |
| * run_time for jobs rather than just its start_time */ |
| error_code = slurm_get_job_steps((time_t) NULL, |
| NO_VAL, NO_VAL, &new_step_ptr, |
| show_flags); |
| if (error_code == SLURM_SUCCESS) { |
| slurm_free_job_step_info_response_msg(g_step_info_ptr); |
| changed = 1; |
| } else if (errno == SLURM_NO_CHANGE_IN_DATA) { |
| error_code = SLURM_NO_CHANGE_IN_DATA; |
| new_step_ptr = g_step_info_ptr; |
| changed = 0; |
| } |
| } else { |
| new_step_ptr = NULL; |
| error_code = slurm_get_job_steps((time_t) NULL, NO_VAL, NO_VAL, |
| &new_step_ptr, show_flags); |
| changed = 1; |
| } |
| |
| g_step_info_ptr = new_step_ptr; |
| |
| if (g_step_info_ptr && (*info_ptr != g_step_info_ptr)) |
| error_code = SLURM_SUCCESS; |
| |
| *info_ptr = g_step_info_ptr; |
| end_it: |
| return error_code; |
| } |
| |
| extern GtkListStore *create_model_job(int type) |
| { |
| GtkListStore *model = NULL; |
| GtkTreeIter iter; |
| |
| last_model = NULL; /* Reformat display */ |
| switch(type) { |
| case SORTID_ACTION: |
| model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); |
| gtk_list_store_append(model, &iter); |
| gtk_list_store_set(model, &iter, |
| 1, SORTID_ACTION, |
| 0, "None", |
| -1); |
| gtk_list_store_append(model, &iter); |
| gtk_list_store_set(model, &iter, |
| 1, SORTID_ACTION, |
| 0, "Cancel", |
| -1); |
| gtk_list_store_append(model, &iter); |
| gtk_list_store_set(model, &iter, |
| 1, SORTID_ACTION, |
| 0, "Suspend/Resume", |
| -1); |
| gtk_list_store_append(model, &iter); |
| gtk_list_store_set(model, &iter, |
| 1, SORTID_ACTION, |
| 0, "Requeue", |
| -1); |
| break; |
| case SORTID_CONTIGUOUS: |
| case SORTID_REBOOT: |
| case SORTID_REQUEUE: |
| case SORTID_OVER_SUBSCRIBE: |
| model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); |
| gtk_list_store_append(model, &iter); |
| gtk_list_store_set(model, &iter, |
| 0, "yes", |
| 1, type, |
| -1); |
| gtk_list_store_append(model, &iter); |
| gtk_list_store_set(model, &iter, |
| 0, "no", |
| 1, type, |
| -1); |
| break; |
| default: |
| break; |
| } |
| |
| return model; |
| } |
| |
| extern void admin_edit_job(GtkCellRendererText *cell, |
| const char *path_string, |
| const char *new_text, |
| gpointer data) |
| { |
| GtkTreeStore *treestore = GTK_TREE_STORE(data); |
| GtkTreePath *path = gtk_tree_path_new_from_string(path_string); |
| GtkTreeIter iter; |
| job_desc_msg_t *job_msg = xmalloc(sizeof(job_desc_msg_t)); |
| char *tmp_jobid = NULL, *offset; |
| |
| char *temp = NULL; |
| char *old_text = NULL; |
| const char *type = NULL; |
| int stepid = NO_VAL; |
| int column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), |
| "column")); |
| |
| if (!new_text || !xstrcmp(new_text, "")) |
| goto no_input; |
| |
| gtk_tree_model_get_iter(GTK_TREE_MODEL(treestore), &iter, path); |
| |
| slurm_init_job_desc_msg(job_msg); |
| gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, |
| SORTID_JOBID, &tmp_jobid, |
| column, &old_text, |
| -1); |
| if (!tmp_jobid) |
| goto no_input; |
| |
| offset = strchr(tmp_jobid, '('); |
| if (offset) |
| offset++; |
| else |
| offset = tmp_jobid; |
| job_msg->job_id = atoi(offset); |
| g_free(tmp_jobid); |
| |
| gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, |
| SORTID_ALLOC, &stepid, -1); |
| if (stepid) |
| stepid = NO_VAL; |
| else { |
| stepid = job_msg->job_id; |
| gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, |
| SORTID_POS, &job_msg->job_id, -1); |
| } |
| |
| type = _set_job_msg(job_msg, new_text, column); |
| if (global_edit_error) |
| goto print_error; |
| |
| if (got_edit_signal) { |
| temp = got_edit_signal; |
| got_edit_signal = NULL; |
| admin_job(GTK_TREE_MODEL(treestore), &iter, temp, NULL); |
| xfree(temp); |
| goto no_input; |
| } |
| |
| if (old_text && !xstrcmp(old_text, new_text)) { |
| temp = g_strdup_printf("No change in value."); |
| } else if (slurm_update_job(job_msg) |
| == SLURM_SUCCESS) { |
| gtk_tree_store_set(treestore, &iter, column, new_text, -1); |
| temp = g_strdup_printf("Job %d %s changed to %s", |
| job_msg->job_id, |
| type, |
| new_text); |
| } else if (errno == ESLURM_DISABLED) { |
| temp = g_strdup_printf( |
| "Can only edit %s on pending jobs.", type); |
| } else { |
| print_error: |
| temp = g_strdup_printf("Job %d %s can't be " |
| "set to %s", |
| job_msg->job_id, |
| type, |
| new_text); |
| } |
| |
| display_edit_note(temp); |
| g_free(temp); |
| |
| no_input: |
| slurm_free_job_desc_msg(job_msg); |
| |
| gtk_tree_path_free (path); |
| g_free(old_text); |
| g_mutex_unlock(sview_mutex); |
| } |
| |
| extern void get_info_job(GtkTable *table, display_data_t *display_data) |
| { |
| int job_error_code = SLURM_SUCCESS; |
| int step_error_code = SLURM_SUCCESS; |
| static int view = -1; |
| static job_info_msg_t *job_info_ptr = NULL; |
| static job_step_info_response_msg_t *step_info_ptr = NULL; |
| char error_char[100]; |
| GtkWidget *label = NULL; |
| GtkTreeView *tree_view = NULL; |
| static GtkWidget *display_widget = NULL; |
| list_t *info_list = NULL; |
| int j, k; |
| sview_job_info_t *sview_job_info_ptr = NULL; |
| job_info_t *job_ptr = NULL; |
| list_itr_t *itr = NULL; |
| GtkTreePath *path = NULL; |
| static bool set_opts = false; |
| |
| if (!set_opts) |
| set_page_opts(JOB_PAGE, display_data_job, |
| SORTID_CNT, _initial_page_opts); |
| set_opts = true; |
| |
| /* reset */ |
| if (!table && !display_data) { |
| if (display_widget) |
| gtk_widget_destroy(display_widget); |
| display_widget = NULL; |
| job_info_ptr = NULL; |
| step_info_ptr = NULL; |
| return; |
| } |
| |
| if (display_data) |
| local_display_data = display_data; |
| if (!table) { |
| display_data_job->set_menu = local_display_data->set_menu; |
| return; |
| } |
| if (display_widget && toggled) { |
| gtk_widget_destroy(display_widget); |
| display_widget = NULL; |
| goto display_it; |
| } |
| |
| if ((job_error_code = get_new_info_job(&job_info_ptr, force_refresh)) |
| == SLURM_NO_CHANGE_IN_DATA){ |
| |
| } else if (job_error_code != SLURM_SUCCESS) { |
| if (view == ERROR_VIEW) |
| goto end_it; |
| if (display_widget) |
| gtk_widget_destroy(display_widget); |
| view = ERROR_VIEW; |
| sprintf(error_char, "slurm_load_jobs: %s", |
| slurm_strerror(errno)); |
| label = gtk_label_new(error_char); |
| gtk_table_attach_defaults(table, label, 0, 1, 0, 1); |
| gtk_widget_show(label); |
| display_widget = g_object_ref(GTK_WIDGET(label)); |
| goto end_it; |
| } |
| |
| if ((step_error_code = get_new_info_job_step(&step_info_ptr, |
| force_refresh)) |
| == SLURM_NO_CHANGE_IN_DATA){ |
| if ((!display_widget || view == ERROR_VIEW) |
| || (step_error_code != SLURM_NO_CHANGE_IN_DATA)) |
| goto display_it; |
| } else if (step_error_code != SLURM_SUCCESS) { |
| if (view == ERROR_VIEW) |
| goto end_it; |
| if (display_widget) |
| gtk_widget_destroy(display_widget); |
| view = ERROR_VIEW; |
| sprintf(error_char, "slurm_load_job_step: %s", |
| slurm_strerror(errno)); |
| label = gtk_label_new(error_char); |
| gtk_table_attach_defaults(table, label, 0, 1, 0, 1); |
| gtk_widget_show(label); |
| display_widget = g_object_ref(GTK_WIDGET(label)); |
| goto end_it; |
| } |
| display_it: |
| |
| info_list = _create_job_info_list(job_info_ptr, step_info_ptr, 0); |
| if (!info_list) |
| goto reset_curs; |
| |
| /* set up the grid */ |
| if (display_widget && GTK_IS_TREE_VIEW(display_widget) |
| && gtk_tree_selection_count_selected_rows( |
| gtk_tree_view_get_selection( |
| GTK_TREE_VIEW(display_widget)))) { |
| GtkTreeViewColumn *focus_column = NULL; |
| /* highlight the correct nodes from the last selection */ |
| gtk_tree_view_get_cursor(GTK_TREE_VIEW(display_widget), |
| &path, &focus_column); |
| } |
| if (!path) { |
| int top_node_inx = 0; |
| int array_size = SVIEW_MAX_NODE_SPACE; |
| int *color_inx = xmalloc(sizeof(int) * array_size); |
| bool *color_set_flag = xmalloc(sizeof(bool) * array_size); |
| itr = list_iterator_create(info_list); |
| while ((sview_job_info_ptr = list_next(itr))) { |
| uint32_t base_state; |
| job_ptr = sview_job_info_ptr->job_ptr; |
| base_state = job_ptr->job_state & JOB_STATE_BASE; |
| if (base_state != JOB_RUNNING) |
| continue; |
| j = 0; |
| while (job_ptr->node_inx[j] >= 0) { |
| top_node_inx = MAX(top_node_inx, |
| job_ptr->node_inx[j+1]); |
| if (top_node_inx > SVIEW_MAX_NODE_SPACE) { |
| fatal("Increase SVIEW_MAX_NODE_SPACE " |
| "in sview"); |
| } |
| for (k = job_ptr->node_inx[j]; |
| k <= job_ptr->node_inx[j+1]; k++) { |
| color_set_flag[k] = true; |
| color_inx[k] = sview_job_info_ptr-> |
| color_inx; |
| } |
| j += 2; |
| } |
| } |
| list_iterator_destroy(itr); |
| change_grid_color_array(grid_button_list, top_node_inx+1, |
| color_inx, color_set_flag, true, 0); |
| xfree(color_inx); |
| xfree(color_set_flag); |
| change_grid_color(grid_button_list, -1, -1, |
| MAKE_WHITE, true, 0); |
| } else { |
| highlight_grid(GTK_TREE_VIEW(display_widget), |
| SORTID_NODE_INX, SORTID_COLOR_INX, |
| grid_button_list); |
| gtk_tree_path_free(path); |
| } |
| |
| if (view == ERROR_VIEW && display_widget) { |
| gtk_widget_destroy(display_widget); |
| display_widget = NULL; |
| } |
| if (!display_widget) { |
| tree_view = create_treeview(local_display_data, |
| &grid_button_list); |
| /* set multiple capability here */ |
| gtk_tree_selection_set_mode( |
| gtk_tree_view_get_selection(tree_view), |
| GTK_SELECTION_MULTIPLE); |
| display_widget = g_object_ref(GTK_WIDGET(tree_view)); |
| gtk_table_attach_defaults(GTK_TABLE(table), |
| GTK_WIDGET(tree_view), |
| 0, 1, 0, 1); |
| /* since this function sets the model of the tree_view to the |
| * treestore we don't really care about the return value */ |
| create_treestore(tree_view, display_data_job, |
| SORTID_CNT, SORTID_TIME_SUBMIT, SORTID_COLOR); |
| |
| set_column_width_fixed(tree_view, SORTID_NODELIST, 100); |
| set_column_width_fixed(tree_view, SORTID_NODELIST_EXC, 100); |
| set_column_width_fixed(tree_view, SORTID_NODELIST_REQ, 100); |
| set_column_width_fixed(tree_view, SORTID_NODELIST_SCHED, 100); |
| } |
| |
| view = INFO_VIEW; |
| /* If the system has a large number of jobs then not all lines |
| * will be displayed. You can try different values for the third |
| * argument of gtk_widget_set_size_request() in an attempt to |
| * maximumize the data displayed in your environment. These are my |
| * results: Y=1000 good for 43 lines, Y=-1 good for 1151 lines, |
| * Y=64000 good for 2781 lines, Y=99000 good for 1453 lines */ |
| /* gtk_widget_set_size_request(display_widget, -1, -1); */ |
| _update_info_job(info_list, GTK_TREE_VIEW(display_widget)); |
| end_it: |
| toggled = false; |
| force_refresh = false; |
| |
| reset_curs: |
| if (main_window && main_window->window) |
| gdk_window_set_cursor(main_window->window, NULL); |
| return; |
| } |
| |
| extern void specific_info_job(popup_info_t *popup_win) |
| { |
| int job_error_code = SLURM_SUCCESS; |
| int step_error_code = SLURM_SUCCESS; |
| static job_info_msg_t *job_info_ptr = NULL; |
| static job_step_info_response_msg_t *step_info_ptr = NULL; |
| specific_info_t *spec_info = popup_win->spec_info; |
| sview_search_info_t *search_info = spec_info->search_info; |
| char error_char[100]; |
| GtkWidget *label = NULL; |
| GtkTreeView *tree_view = NULL; |
| list_t *info_list = NULL; |
| list_t *send_info_list = NULL; |
| int j, k; |
| sview_job_info_t *sview_job_info_ptr = NULL; |
| job_info_t *job_ptr = NULL; |
| list_itr_t *itr = NULL; |
| char *uname = NULL; |
| hostset_t *hostset = NULL; |
| int name_diff; |
| int top_node_inx, array_size, *color_inx; |
| bool *color_set_flag; |
| |
| if (!spec_info->display_widget) |
| setup_popup_info(popup_win, display_data_job, SORTID_CNT); |
| |
| if (spec_info->display_widget && popup_win->toggled) { |
| gtk_widget_destroy(spec_info->display_widget); |
| spec_info->display_widget = NULL; |
| goto display_it; |
| } |
| |
| if ((job_error_code = |
| get_new_info_job(&job_info_ptr, popup_win->force_refresh)) |
| == SLURM_NO_CHANGE_IN_DATA) { |
| |
| } else if (job_error_code != SLURM_SUCCESS) { |
| if (spec_info->view == ERROR_VIEW) |
| goto end_it; |
| spec_info->view = ERROR_VIEW; |
| if (spec_info->display_widget) |
| gtk_widget_destroy(spec_info->display_widget); |
| |
| sprintf(error_char, "slurm_load_jobs: %s", |
| slurm_strerror(errno)); |
| label = gtk_label_new(error_char); |
| gtk_table_attach_defaults(GTK_TABLE(popup_win->table), |
| label, |
| 0, 1, 0, 1); |
| gtk_widget_show(label); |
| spec_info->display_widget = g_object_ref(GTK_WIDGET(label)); |
| goto end_it; |
| } |
| |
| if ((step_error_code = |
| get_new_info_job_step(&step_info_ptr, popup_win->force_refresh)) |
| == SLURM_NO_CHANGE_IN_DATA) { |
| if ((!spec_info->display_widget |
| || spec_info->view == ERROR_VIEW) |
| || (step_error_code != SLURM_NO_CHANGE_IN_DATA)) |
| goto display_it; |
| } else if (step_error_code != SLURM_SUCCESS) { |
| if (spec_info->view == ERROR_VIEW) |
| goto end_it; |
| if (spec_info->display_widget) |
| gtk_widget_destroy(spec_info->display_widget); |
| spec_info->view = ERROR_VIEW; |
| sprintf(error_char, "slurm_load_job_step: %s", |
| slurm_strerror(errno)); |
| label = gtk_label_new(error_char); |
| gtk_table_attach_defaults(popup_win->table, label, |
| 0, 1, 0, 1); |
| gtk_widget_show(label); |
| spec_info->display_widget = g_object_ref(GTK_WIDGET(label)); |
| goto end_it; |
| } |
| display_it: |
| info_list = _create_job_info_list(job_info_ptr, step_info_ptr, 1); |
| if (!info_list) |
| return; |
| |
| if (spec_info->view == ERROR_VIEW && spec_info->display_widget) { |
| gtk_widget_destroy(spec_info->display_widget); |
| spec_info->display_widget = NULL; |
| } |
| |
| if (spec_info->type != INFO_PAGE && !spec_info->display_widget) { |
| tree_view = create_treeview(local_display_data, |
| &popup_win->grid_button_list); |
| /*set multiple capability here*/ |
| gtk_tree_selection_set_mode( |
| gtk_tree_view_get_selection(tree_view), |
| GTK_SELECTION_MULTIPLE); |
| spec_info->display_widget = |
| g_object_ref(GTK_WIDGET(tree_view)); |
| gtk_table_attach_defaults(popup_win->table, |
| GTK_WIDGET(tree_view), |
| 0, 1, 0, 1); |
| /* since this function sets the model of the tree_view to the |
| * treestore we don't really care about the return value */ |
| create_treestore(tree_view, popup_win->display_data, |
| SORTID_CNT, SORTID_TIME_SUBMIT, SORTID_COLOR); |
| } |
| |
| setup_popup_grid_list(popup_win); |
| |
| spec_info->view = INFO_VIEW; |
| if (spec_info->type == INFO_PAGE) { |
| _display_info_job(info_list, popup_win); |
| goto end_it; |
| } |
| |
| |
| /* just linking to another list, don't free the inside, just |
| * the list */ |
| send_info_list = list_create(NULL); |
| itr = list_iterator_create(info_list); |
| while ((sview_job_info_ptr = list_next(itr))) { |
| job_ptr = sview_job_info_ptr->job_ptr; |
| switch (spec_info->type) { |
| case JOB_PAGE: |
| switch(search_info->search_type) { |
| case SEARCH_JOB_ID: |
| if (search_info->int_data |
| == NO_VAL) { |
| if (!search_info->gchar_data) |
| continue; |
| _convert_char_to_job_and_step( |
| search_info->gchar_data, |
| &search_info->int_data, |
| &search_info->int_data2); |
| } |
| if (job_ptr->job_id != search_info->int_data) { |
| continue; |
| } |
| #if 0 |
| /* if we ever want to display just the step |
| * this is where we would do it */ |
| if (spec_info->search_info->int_data2 |
| == NO_VAL) |
| break; |
| step_itr = list_iterator_create( |
| sview_job_info->step_list); |
| while ((step_ptr = list_next(itr))) { |
| if (step_ptr->step_id.step_id == |
| spec_info->search_info->int_data2) { |
| break; |
| } |
| } |
| #endif |
| break; |
| case SEARCH_JOB_USER: |
| if (!search_info->gchar_data) |
| continue; |
| uname = uid_to_string_cached(job_ptr->user_id); |
| name_diff = xstrcmp(uname, |
| search_info->gchar_data); |
| if (name_diff) |
| continue; |
| break; |
| case SEARCH_JOB_STATE: |
| if (search_info->int_data == NO_VAL) |
| continue; |
| |
| if (job_ptr->job_state != search_info->int_data) |
| continue; |
| break; |
| default: |
| break; |
| } |
| break; |
| case PART_PAGE: |
| if (xstrcmp(search_info->gchar_data, |
| job_ptr->partition)) |
| continue; |
| |
| if (search_info->cluster_name && |
| xstrcmp(search_info->cluster_name, |
| job_ptr->cluster)) |
| continue; |
| break; |
| case RESV_PAGE: |
| if (!job_ptr->resv_name |
| || xstrcmp(search_info->gchar_data, |
| job_ptr->resv_name)) |
| continue; |
| break; |
| case NODE_PAGE: |
| if (!job_ptr->nodes) |
| continue; |
| |
| if (!(hostset = hostset_create( |
| search_info->gchar_data))) |
| continue; |
| if (!hostset_intersects(hostset, job_ptr->nodes)) { |
| hostset_destroy(hostset); |
| continue; |
| } |
| hostset_destroy(hostset); |
| break; |
| default: |
| continue; |
| } |
| |
| list_push(send_info_list, sview_job_info_ptr); |
| top_node_inx = 0; |
| array_size = SVIEW_MAX_NODE_SPACE; |
| color_inx = xmalloc(sizeof(int) * array_size); |
| color_set_flag = xmalloc(sizeof(bool) * array_size); |
| j = 0; |
| while (job_ptr->node_inx[j] >= 0) { |
| top_node_inx = MAX(top_node_inx, |
| job_ptr->node_inx[j+1]); |
| if (top_node_inx > SVIEW_MAX_NODE_SPACE) |
| fatal("Increase SVIEW_MAX_NODE_SPACE in sview"); |
| for (k = job_ptr->node_inx[j]; |
| k <= job_ptr->node_inx[j+1]; k++) { |
| color_set_flag[k] = true; |
| color_inx[k] = sview_job_info_ptr->color_inx; |
| } |
| j += 2; |
| } |
| change_grid_color_array(popup_win->grid_button_list, |
| top_node_inx+1, color_inx, |
| color_set_flag, true, 0); |
| xfree(color_inx); |
| xfree(color_set_flag); |
| } |
| list_iterator_destroy(itr); |
| post_setup_popup_grid_list(popup_win); |
| |
| _update_info_job(send_info_list, |
| GTK_TREE_VIEW(spec_info->display_widget)); |
| |
| FREE_NULL_LIST(send_info_list); |
| end_it: |
| popup_win->toggled = 0; |
| popup_win->force_refresh = 0; |
| return; |
| } |
| |
| extern void set_menus_job(void *arg, void *arg2, GtkTreePath *path, int type) |
| { |
| GtkTreeView *tree_view = (GtkTreeView *)arg; |
| popup_info_t *popup_win = (popup_info_t *)arg; |
| GtkMenu *menu = (GtkMenu *)arg2; |
| list_t *button_list = arg2; |
| |
| switch(type) { |
| case TAB_CLICKED: |
| make_fields_menu(NULL, menu, display_data_job, SORTID_CNT); |
| break; |
| case ROW_CLICKED: |
| make_options_menu(tree_view, path, menu, options_data_job); |
| break; |
| case ROW_LEFT_CLICKED: |
| highlight_grid(tree_view, SORTID_NODE_INX, |
| SORTID_COLOR_INX, button_list); |
| break; |
| case FULL_CLICKED: |
| { |
| GtkTreeModel *model = gtk_tree_view_get_model(tree_view); |
| GtkTreeIter iter; |
| if (!gtk_tree_model_get_iter(model, &iter, path)) { |
| g_error("job error getting iter from model\n"); |
| break; |
| } |
| |
| popup_all_job(model, &iter, INFO_PAGE); |
| |
| break; |
| } |
| case POPUP_CLICKED: |
| make_fields_menu(popup_win, menu, |
| popup_win->display_data, SORTID_CNT); |
| break; |
| default: |
| g_error("UNKNOWN type %d given to set_fields\n", type); |
| } |
| } |
| |
| extern void popup_all_job(GtkTreeModel *model, GtkTreeIter *iter, int id) |
| { |
| char *name = NULL, *cluster_name = NULL; |
| char title[100] = {0}; |
| list_itr_t *itr = NULL; |
| popup_info_t *popup_win = NULL; |
| int jobid = NO_VAL; |
| int stepid = NO_VAL; |
| GError *error = NULL; |
| char *tmp_jobid = NULL, *offset; |
| |
| gtk_tree_model_get(model, iter, SORTID_JOBID, &tmp_jobid, -1); |
| if (!tmp_jobid) |
| return; |
| |
| offset = strchr(tmp_jobid, '('); |
| if (offset) |
| offset++; |
| else |
| offset = tmp_jobid; |
| jobid = _id_from_stepstr(offset); |
| g_free(tmp_jobid); |
| gtk_tree_model_get(model, iter, SORTID_JOBID_FORMATTED, &tmp_jobid, -1); |
| gtk_tree_model_get(model, iter, SORTID_CLUSTER_NAME, &cluster_name, -1); |
| |
| gtk_tree_model_get(model, iter, SORTID_ALLOC, &stepid, -1); |
| |
| if (stepid) |
| stepid = NO_VAL; |
| else { |
| stepid = jobid; |
| gtk_tree_model_get(model, iter, SORTID_POS, &jobid, -1); |
| } |
| |
| switch(id) { |
| case PART_PAGE: |
| if (stepid == NO_VAL) |
| snprintf(title, 100, "Partition with job %s", |
| tmp_jobid); |
| else |
| snprintf(title, 100, "Partition with job step %s", |
| tmp_jobid); |
| break; |
| case RESV_PAGE: |
| if (stepid == NO_VAL) |
| snprintf(title, 100, "Reservation with job %s", |
| tmp_jobid); |
| else |
| snprintf(title, 100, "Reservation with job step %s", |
| tmp_jobid); |
| break; |
| case NODE_PAGE: |
| if (stepid == NO_VAL) |
| snprintf(title, 100, |
| "Node(s) running job %s", tmp_jobid); |
| else |
| snprintf(title, 100, "Node(s) running job step %s", |
| tmp_jobid); |
| break; |
| case INFO_PAGE: |
| if (stepid == NO_VAL) |
| snprintf(title, 100, "Full info for job %s", tmp_jobid); |
| else |
| snprintf(title, 100, "Full info for job step %s", |
| tmp_jobid); |
| break; |
| default: |
| g_print("jobs got id %d\n", id); |
| } |
| |
| if (cluster_name && federation_name && |
| (cluster_flags & CLUSTER_FLAG_FED)) { |
| char *tmp_cname = |
| xstrdup_printf(" (%s:%s)", |
| federation_name, cluster_name); |
| strncat(title, tmp_cname, sizeof(title) - strlen(title) - 1); |
| xfree(tmp_cname); |
| } |
| |
| if (tmp_jobid) |
| g_free(tmp_jobid); |
| |
| itr = list_iterator_create(popup_list); |
| while ((popup_win = list_next(itr))) { |
| if (popup_win->spec_info) |
| if (!xstrcmp(popup_win->spec_info->title, title)) { |
| break; |
| } |
| } |
| list_iterator_destroy(itr); |
| |
| if (!popup_win) { |
| if (id == INFO_PAGE) |
| popup_win = create_popup_info(id, JOB_PAGE, title); |
| else |
| popup_win = create_popup_info(JOB_PAGE, id, title); |
| } else { |
| gtk_window_present(GTK_WINDOW(popup_win->popup)); |
| g_free(cluster_name); |
| return; |
| } |
| |
| /* Pass the model and the structs from the iter so we can always get |
| the current node_inx. |
| */ |
| popup_win->model = model; |
| popup_win->iter = *iter; |
| popup_win->node_inx_id = SORTID_NODE_INX; |
| |
| if (cluster_flags & CLUSTER_FLAG_FED) { |
| popup_win->spec_info->search_info->cluster_name = cluster_name; |
| cluster_name = NULL; |
| } |
| g_free(cluster_name); |
| |
| switch(id) { |
| case NODE_PAGE: |
| gtk_tree_model_get(model, iter, SORTID_NODELIST, &name, -1); |
| popup_win->spec_info->search_info->gchar_data = name; |
| break; |
| case PART_PAGE: |
| gtk_tree_model_get(model, iter, SORTID_PARTITION, &name, -1); |
| popup_win->spec_info->search_info->gchar_data = name; |
| break; |
| case RESV_PAGE: |
| gtk_tree_model_get(model, iter, SORTID_RESV_NAME, &name, -1); |
| popup_win->spec_info->search_info->gchar_data = name; |
| break; |
| case SUBMIT_PAGE: |
| break; |
| case INFO_PAGE: |
| popup_win->spec_info->search_info->int_data = jobid; |
| popup_win->spec_info->search_info->int_data2 = stepid; |
| break; |
| |
| default: |
| g_print("jobs got %d\n", id); |
| } |
| if (!sview_thread_new((gpointer)popup_thr, popup_win, &error)) { |
| g_printerr ("Failed to create part popup thread: %s\n", |
| error->message); |
| return; |
| } |
| } |
| |
| static void process_foreach_list(jobs_foreach_common_t *jobs_foreach_common) |
| { |
| int jobid; |
| int state; |
| int stepid; |
| uint16_t signal = SIGKILL; |
| int response = 0; |
| char *tmp_char_ptr = ""; |
| jobs_foreach_t *job_foreach = NULL; |
| list_itr_t *itr = NULL; |
| |
| if (jobs_foreach_common->edit_type == EDIT_SIGNAL) { |
| const gchar *entry_txt = gtk_entry_get_text( |
| GTK_ENTRY(jobs_foreach_common->entry)); |
| signal = _xlate_signal_name(entry_txt); |
| if (signal == NO_VAL16) { |
| tmp_char_ptr = g_strdup_printf( |
| "%s is not a valid signal.", |
| entry_txt); |
| display_edit_note(tmp_char_ptr); |
| g_free(tmp_char_ptr); |
| goto end_it; |
| } |
| } |
| |
| itr = list_iterator_create(foreach_list); |
| while ((job_foreach = list_next(itr))) { |
| /*stop processing remaining jobs on any error*/ |
| if (global_error_code) |
| break; |
| |
| jobid = job_foreach->step_id.job_id; |
| stepid = job_foreach->step_id.step_id; |
| state = job_foreach->state; |
| |
| switch(jobs_foreach_common->edit_type) { |
| case EDIT_SIGNAL: |
| /* fall through to the cancel now the signal |
| * is set (Default is SIGKILL from above for |
| * just a regular cancel). |
| */ |
| case EDIT_CANCEL: |
| if (stepid == NO_VAL) |
| global_error_code = |
| _cancel_job_id(jobid, signal); |
| else |
| global_error_code = |
| _cancel_step_id(jobid, |
| stepid, signal); |
| break; |
| case EDIT_REQUEUE: |
| response = slurm_requeue(jobid, 0); |
| |
| if (response) { |
| /* stop rest of jobs */ |
| global_error_code = response; |
| tmp_char_ptr = g_strdup_printf( |
| "Error happened trying " |
| "to requeue job %u: %s", |
| jobid, slurm_strerror(response)); |
| display_edit_note(tmp_char_ptr); |
| g_free(tmp_char_ptr); |
| } |
| break; |
| case EDIT_SUSPEND: |
| //note: derive state from job_foreach.. |
| if (state == JOB_SUSPENDED) |
| response = slurm_resume(jobid); |
| else |
| response = slurm_suspend(jobid); |
| if (!response) { |
| /* stop rest of jobs */ |
| global_error_code = response; |
| tmp_char_ptr = g_strdup_printf( |
| "Error happened trying to " |
| "SUSPEND/RESUME job %u.", |
| jobid); |
| display_edit_note(tmp_char_ptr); |
| g_free(tmp_char_ptr); |
| } |
| break; |
| default: |
| break; |
| |
| }/*end switch*/ |
| } /*spin thru selected jobs*/ |
| |
| if (global_edit_error || global_error_code) |
| goto end_it; |
| |
| switch (jobs_foreach_common->edit_type) { |
| case EDIT_SIGNAL: |
| tmp_char_ptr = g_strdup_printf( |
| "Signal successfully sent to job(s)%s", |
| stacked_job_list); |
| display_edit_note(tmp_char_ptr); |
| g_free(tmp_char_ptr); |
| break; |
| case EDIT_CANCEL: |
| tmp_char_ptr = g_strdup_printf( |
| "Cancel successful for job(s)%s", |
| stacked_job_list); |
| display_edit_note(tmp_char_ptr); |
| g_free(tmp_char_ptr); |
| break; |
| case EDIT_REQUEUE: |
| tmp_char_ptr = g_strdup_printf( |
| "Requeue successful for job(s)%s", |
| stacked_job_list); |
| display_edit_note(tmp_char_ptr); |
| g_free(tmp_char_ptr); |
| break; |
| case EDIT_SUSPEND: |
| tmp_char_ptr = g_strdup_printf( |
| "SUSPEND/RESUME action successful for job(s)%s", |
| stacked_job_list); |
| display_edit_note(tmp_char_ptr); |
| g_free(tmp_char_ptr); |
| break; |
| default: |
| break; |
| |
| }/*end switch*/ |
| |
| end_it: |
| xfree(stacked_job_list); |
| |
| } /*process_foreach_list ^^^*/ |
| |
| static void selected_foreach_build_list(GtkTreeModel *model, |
| GtkTreePath *path, |
| GtkTreeIter *iter, |
| gpointer userdata) |
| { |
| uint32_t jobid = NO_VAL; |
| uint32_t stepid = NO_VAL; |
| uint32_t array_job_id = NO_VAL, array_task_id = NO_VAL; |
| uint32_t het_job_id = NO_VAL, het_job_offset = NO_VAL; |
| int state; |
| jobs_foreach_t *fe_ptr = NULL; |
| char *tmp_jobid, *offset, *end_ptr; |
| |
| gtk_tree_model_get(model, iter, SORTID_JOBID, &tmp_jobid, -1); |
| |
| if (!tmp_jobid) |
| return; |
| |
| offset = strchr(tmp_jobid, '('); |
| if (offset) { |
| if (strchr(tmp_jobid, '_')) { |
| array_job_id = strtol(tmp_jobid, &end_ptr, 10); |
| array_task_id = strtol(end_ptr+1, NULL, 10); |
| } else { |
| het_job_id = strtol(tmp_jobid, &end_ptr, 10); |
| het_job_offset = strtol(end_ptr+1, NULL, 10); |
| } |
| offset++; |
| } else |
| offset = tmp_jobid; |
| jobid = atoi(offset); |
| g_free(tmp_jobid); |
| |
| gtk_tree_model_get(model, iter, SORTID_ALLOC, &stepid, -1); |
| |
| if (stepid) |
| stepid = NO_VAL; |
| else { |
| stepid = jobid; |
| gtk_tree_model_get(model, iter, SORTID_POS, &jobid, -1); |
| } |
| |
| gtk_tree_model_get(model, iter, SORTID_STATE_NUM, &state, -1); |
| |
| /* alc mem for individual job processor target */ |
| fe_ptr = xmalloc(sizeof(jobs_foreach_t)); |
| fe_ptr->step_id.job_id = jobid; |
| fe_ptr->step_id.step_id = stepid; |
| fe_ptr->step_id.step_het_comp = NO_VAL; |
| fe_ptr->state = state; |
| fe_ptr->array_job_id = array_job_id; |
| fe_ptr->array_task_id = array_task_id; |
| fe_ptr->het_job_id = het_job_id; |
| fe_ptr->het_job_offset = het_job_offset; |
| |
| list_append(foreach_list, fe_ptr); /* stuff target away*/ |
| |
| if (stacked_job_list) |
| xstrcat(stacked_job_list, ", "); |
| else |
| xstrcat(stacked_job_list, ": "); |
| |
| if (array_task_id == NO_VAL && het_job_id == NO_VAL) |
| xstrfmtcat(stacked_job_list, "%u", jobid); |
| else if (het_job_id != NO_VAL) |
| xstrfmtcat(stacked_job_list, "%u+%u", het_job_id, |
| het_job_offset); |
| else |
| xstrfmtcat(stacked_job_list, "%u_%u", |
| array_job_id, array_task_id); |
| if (stepid != SLURM_BATCH_SCRIPT) |
| xstrfmtcat(stacked_job_list, ".%u", stepid); |
| } |
| |
| static void _edit_each_job(GtkTreeModel *model, GtkTreeIter *iter, |
| jobs_foreach_common_t *jobs_foreach_common) |
| { |
| int response; |
| GtkWidget *popup; |
| GtkWidget *label = NULL; |
| GtkWidget *entry = NULL; |
| char tmp_char[255]; |
| char *tmp_char_ptr = ""; |
| jobs_foreach_t *job_foreach = NULL; |
| job_desc_msg_t *job_msg; |
| list_itr_t *itr = NULL; |
| |
| itr = list_iterator_create(foreach_list); |
| while ((job_foreach = list_next(itr))) { |
| /*stop processing remaining jobs on any error*/ |
| if (global_error_code || got_edit_signal) |
| break; |
| |
| popup = gtk_dialog_new_with_buttons( |
| "Edit Job", |
| GTK_WINDOW(main_window), |
| GTK_DIALOG_MODAL | |
| GTK_DIALOG_DESTROY_WITH_PARENT, |
| NULL); |
| gtk_window_set_type_hint(GTK_WINDOW(popup), |
| GDK_WINDOW_TYPE_HINT_NORMAL); |
| gtk_window_set_transient_for(GTK_WINDOW(popup), NULL); |
| label = gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_OK, GTK_RESPONSE_OK); |
| gtk_window_set_default(GTK_WINDOW(popup), label); |
| gtk_dialog_add_button(GTK_DIALOG(popup), GTK_STOCK_CANCEL, |
| GTK_RESPONSE_CANCEL); |
| gtk_dialog_add_button(GTK_DIALOG(popup), "Cancel all", |
| GTK_RESPONSE_DELETE_EVENT); |
| gtk_window_set_default_size(GTK_WINDOW(popup), 200, 400); |
| snprintf(tmp_char, sizeof(tmp_char), |
| "Editing job %u think before you type", |
| job_foreach->step_id.job_id); |
| label = gtk_label_new(tmp_char); |
| |
| job_msg = xmalloc(sizeof(job_desc_msg_t)); |
| slurm_init_job_desc_msg(job_msg); |
| job_msg->job_id = job_foreach->step_id.job_id; |
| entry = _admin_full_edit_job(job_msg, model, iter); |
| gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), |
| label, false, false, 0); |
| if (entry) |
| gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), |
| entry, true, true, 0); |
| gtk_widget_show_all(popup); |
| response = gtk_dialog_run(GTK_DIALOG(popup)); |
| gtk_widget_destroy(popup); |
| |
| if (got_edit_signal || |
| (response == GTK_RESPONSE_DELETE_EVENT)) { |
| slurm_free_job_desc_msg(job_msg); |
| break; |
| } |
| |
| if (global_edit_error) { |
| tmp_char_ptr = global_edit_error_msg; |
| } else if (!global_send_update_msg || |
| (response == GTK_RESPONSE_CANCEL)) { |
| tmp_char_ptr = g_strdup_printf("No change detected."); |
| } else if (slurm_update_job(job_msg) |
| == SLURM_SUCCESS) { |
| tmp_char_ptr = g_strdup_printf( |
| "Job %u updated successfully", |
| job_foreach->step_id.job_id); |
| } else if (errno == ESLURM_DISABLED) { |
| tmp_char_ptr = g_strdup_printf( |
| "Can't edit that part of non-pending job %u.", |
| job_foreach->step_id.job_id); |
| } else { |
| tmp_char_ptr = g_strdup_printf( |
| "Problem updating job %u.", |
| job_foreach->step_id.job_id); |
| } |
| display_edit_note(tmp_char_ptr); |
| g_free(tmp_char_ptr); |
| slurm_free_job_desc_msg(job_msg); |
| } /*spin thru selected jobs*/ |
| |
| xfree(stacked_job_list); |
| |
| } /*process_foreach_list ^^^*/ |
| |
| static void _edit_jobs(GtkTreeModel *model, GtkTreeIter *iter, |
| char *type, GtkTreeView *treeview) |
| { |
| jobs_foreach_common_t job_foreach_common; |
| global_error_code = SLURM_SUCCESS; |
| /* setup working_sview_config that applies to ALL selections */ |
| memset(&job_foreach_common, 0, sizeof(jobs_foreach_common_t)); |
| job_foreach_common.type = type; |
| job_foreach_common.edit_type = EDIT_EDIT; |
| |
| /* create a list to stack the selected jobs */ |
| foreach_list = list_create(xfree_ptr); |
| /* build array of job(s) to process */ |
| if (treeview) { |
| gtk_tree_selection_selected_foreach( |
| gtk_tree_view_get_selection(treeview), |
| selected_foreach_build_list, NULL); |
| } else |
| selected_foreach_build_list(model, NULL, iter, NULL); |
| /* determine what to do with them/it */ |
| _edit_each_job(model, iter, &job_foreach_common); /*go do them*/ |
| FREE_NULL_LIST(foreach_list); |
| |
| return; |
| |
| } |
| |
| extern void admin_job(GtkTreeModel *model, GtkTreeIter *iter, |
| char *type, GtkTreeView *treeview) |
| { |
| int jobid = NO_VAL; |
| int stepid = NO_VAL; |
| int response = 0; |
| char tmp_char[255]; |
| int edit_type = 0; |
| job_desc_msg_t *job_msg; |
| GtkWidget *label = NULL; |
| GtkWidget *entry = NULL; |
| GtkWidget *popup; |
| char *tmp_jobid, *offset; |
| |
| if (xstrcmp(type, "Edit Job") == 0) |
| return _edit_jobs(model, iter, type, treeview); |
| |
| popup = gtk_dialog_new_with_buttons( |
| type, |
| GTK_WINDOW(main_window), |
| GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, |
| NULL); |
| gtk_window_set_type_hint(GTK_WINDOW(popup), |
| GDK_WINDOW_TYPE_HINT_NORMAL); |
| |
| gtk_window_set_transient_for(GTK_WINDOW(popup), NULL); |
| |
| gtk_tree_model_get(model, iter, SORTID_JOBID, &tmp_jobid, -1); |
| |
| if (!tmp_jobid) |
| return; |
| |
| offset = strchr(tmp_jobid, '('); |
| if (offset) |
| offset++; |
| else |
| offset = tmp_jobid; |
| jobid = atoi(offset); |
| g_free(tmp_jobid); |
| |
| gtk_tree_model_get(model, iter, SORTID_ALLOC, &stepid, -1); |
| if (stepid) |
| stepid = NO_VAL; |
| else { |
| stepid = jobid; |
| gtk_tree_model_get(model, iter, SORTID_POS, &jobid, -1); |
| } |
| |
| job_msg = xmalloc(sizeof(job_desc_msg_t)); |
| slurm_init_job_desc_msg(job_msg); |
| |
| if (!xstrcasecmp("Signal", type)) { |
| label = gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_OK, GTK_RESPONSE_OK); |
| gtk_window_set_default(GTK_WINDOW(popup), label); |
| gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); |
| |
| entry = create_entry(); |
| label = gtk_label_new("Signal?"); |
| edit_type = EDIT_SIGNAL; |
| } else if (!xstrcasecmp("Requeue", type)) { |
| label = gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_YES, GTK_RESPONSE_OK); |
| gtk_window_set_default(GTK_WINDOW(popup), label); |
| gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); |
| snprintf(tmp_char, sizeof(tmp_char), |
| "Are you sure you want to requeue these job(s)?"); |
| label = gtk_label_new(tmp_char); |
| edit_type = EDIT_REQUEUE; |
| } else if (!xstrcasecmp("Cancel", type)) { |
| label = gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_YES, GTK_RESPONSE_OK); |
| gtk_window_set_default(GTK_WINDOW(popup), label); |
| gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_NO, GTK_RESPONSE_CANCEL); |
| |
| if (stepid != SLURM_BATCH_SCRIPT) |
| snprintf(tmp_char, sizeof(tmp_char), |
| "Are you sure you want to cancel " |
| "these job step(s)?"); |
| else |
| snprintf(tmp_char, sizeof(tmp_char), |
| "Are you sure you want to cancel " |
| "these job(s)?"); |
| label = gtk_label_new(tmp_char); |
| edit_type = EDIT_CANCEL; |
| } else if (!xstrcasecmp("Suspend/Resume", type)) { |
| label = gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_YES, GTK_RESPONSE_OK); |
| gtk_window_set_default(GTK_WINDOW(popup), label); |
| gtk_dialog_add_button(GTK_DIALOG(popup), |
| GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); |
| |
| if (stepid != SLURM_BATCH_SCRIPT) |
| snprintf(tmp_char, sizeof(tmp_char), |
| "Are you sure you want to toggle " |
| "suspend/resume on these job steps?"); |
| else |
| snprintf(tmp_char, sizeof(tmp_char), |
| "Are you sure you want to toggle " |
| "suspend/resume on these jobs?"); |
| label = gtk_label_new(tmp_char); |
| edit_type = EDIT_SUSPEND; |
| } |
| |
| gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), |
| label, false, false, 0); |
| if (entry) |
| gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), |
| entry, true, true, 0); |
| gtk_widget_show_all(popup); |
| response = gtk_dialog_run (GTK_DIALOG(popup)); |
| |
| if (response == GTK_RESPONSE_OK) { |
| jobs_foreach_common_t job_foreach_common; |
| global_error_code = SLURM_SUCCESS; |
| /* setup working_sview_config that applies to ALL selections */ |
| memset(&job_foreach_common, 0, sizeof(jobs_foreach_common_t)); |
| job_foreach_common.type = type; |
| job_foreach_common.edit_type = edit_type; |
| job_foreach_common.entry = entry; |
| |
| /* pass this ptr for single job selections */ |
| job_foreach_common.job_msg = job_msg; |
| |
| /* create a list to stack the selected jobs */ |
| foreach_list = list_create(xfree_ptr); |
| /* build array of job(s) to process */ |
| if (treeview) |
| gtk_tree_selection_selected_foreach( |
| gtk_tree_view_get_selection(treeview), |
| selected_foreach_build_list, NULL); |
| else |
| selected_foreach_build_list(model, NULL, iter, NULL); |
| /* determine what to do with them/it */ |
| process_foreach_list(&job_foreach_common); /*go do them*/ |
| FREE_NULL_LIST(foreach_list); |
| }/*response OK ^^*/ |
| /* switch back to standard cursor*/ |
| |
| global_entry_changed = 0; |
| slurm_free_job_desc_msg(job_msg); |
| gtk_widget_destroy(popup); |
| if (got_edit_signal) { |
| type = got_edit_signal; |
| got_edit_signal = NULL; |
| admin_job(model, iter, type, treeview); |
| xfree(type); |
| } |
| return; |
| } |
| |
| extern void cluster_change_job(void) |
| { |
| display_data_t *display_data = display_data_job; |
| while (display_data++) { |
| if (display_data->id == -1) |
| break; |
| |
| if (cluster_flags & CLUSTER_FLAG_FED) { |
| switch(display_data->id) { |
| case SORTID_CLUSTER_NAME: |
| display_data->show = true; |
| break; |
| } |
| } else { |
| switch(display_data->id) { |
| case SORTID_CLUSTER_NAME: |
| display_data->show = false; |
| break; |
| } |
| } |
| } |
| |
| get_info_job(NULL, NULL); |
| } |