1 /*
2 * job.c - convert data between job (step) related messages and perl HVs
3 */
4
5 #include <EXTERN.h>
6 #include <perl.h>
7 #include <XSUB.h>
8 #include <slurm/slurm.h>
9 #include "ppport.h"
10
11 #undef VERSION /* MakeMaker defines VERSION to some version we don't care
12 * about. The true version will be defined in config.h which is
13 * included from src/common/job_resources.h below.
14 */
15
16 #include "src/common/job_resources.h"
17
18 #include "bitstr.h"
19 #include "slurm-perl.h"
20
21 static node_info_msg_t *job_node_ptr = NULL;
22
23 /* This set of functions loads/free node information so that we can map a job's
24 * core bitmap to it's CPU IDs based upon the thread count on each node. */
_load_node_info(void)25 static void _load_node_info(void)
26 {
27 if (!job_node_ptr)
28 (void) slurm_load_node((time_t) NULL, &job_node_ptr, 0);
29 }
30
_free_node_info(void)31 static void _free_node_info(void)
32 {
33 if (job_node_ptr) {
34 slurm_free_node_info_msg(job_node_ptr);
35 job_node_ptr = NULL;
36 }
37 }
38
_threads_per_core(char * host)39 static uint32_t _threads_per_core(char *host)
40 {
41 uint32_t i, threads = 1;
42
43 if (!job_node_ptr || !host)
44 return threads;
45
46 for (i = 0; i < job_node_ptr->record_count; i++) {
47 if (job_node_ptr->node_array[i].name &&
48 !strcmp(host, job_node_ptr->node_array[i].name)) {
49 threads = job_node_ptr->node_array[i].threads;
50 break;
51 }
52 }
53
54 return threads;
55 }
56
_job_resrcs_to_hv(job_info_t * job_info,HV * hv)57 static int _job_resrcs_to_hv(job_info_t *job_info, HV *hv)
58 {
59 AV *av;
60 HV *nr_hv;
61 bitstr_t *cpu_bitmap;
62 int sock_inx, sock_reps, last, cnt = 0, i, j, k;
63 char tmp1[128], tmp2[128];
64 char *host;
65 job_resources_t *job_resrcs = job_info->job_resrcs;
66 int bit_inx, bit_reps;
67 int abs_node_inx, rel_node_inx;
68 uint64_t *last_mem_alloc_ptr = NULL;
69 uint64_t last_mem_alloc = NO_VAL64;
70 char *last_hosts;
71 hostlist_t hl, hl_last;
72 uint32_t threads;
73
74 if (!job_resrcs || !job_resrcs->core_bitmap
75 || ((last = slurm_bit_fls(job_resrcs->core_bitmap)) == -1))
76 return 0;
77
78 if (!(hl = slurm_hostlist_create(job_resrcs->nodes)))
79 return 1;
80
81 if (!(hl_last = slurm_hostlist_create(NULL)))
82 return 1;
83 av = newAV();
84
85 bit_inx = 0;
86 i = sock_inx = sock_reps = 0;
87 abs_node_inx = job_info->node_inx[i];
88
89 /* tmp1[] stores the current cpu(s) allocated */
90 tmp2[0] = '\0'; /* stores last cpu(s) allocated */
91 for (rel_node_inx=0; rel_node_inx < job_resrcs->nhosts;
92 rel_node_inx++) {
93
94 if (sock_reps >= job_resrcs->sock_core_rep_count[sock_inx]) {
95 sock_inx++;
96 sock_reps = 0;
97 }
98 sock_reps++;
99
100 bit_reps = job_resrcs->sockets_per_node[sock_inx] *
101 job_resrcs->cores_per_socket[sock_inx];
102 host = slurm_hostlist_shift(hl);
103 threads = _threads_per_core(host);
104 cpu_bitmap = slurm_bit_alloc(bit_reps * threads);
105 for (j = 0; j < bit_reps; j++) {
106 if (slurm_bit_test(job_resrcs->core_bitmap, bit_inx)){
107 for (k = 0; k < threads; k++)
108 slurm_bit_set(cpu_bitmap,
109 (j * threads) + k);
110 }
111 bit_inx++;
112 }
113 slurm_bit_fmt(tmp1, sizeof(tmp1), cpu_bitmap);
114 FREE_NULL_BITMAP(cpu_bitmap);
115 /*
116 * If the allocation values for this host are not the same as the
117 * last host, print the report of the last group of hosts that had
118 * identical allocation values.
119 */
120 if (strcmp(tmp1, tmp2) ||
121 (last_mem_alloc_ptr != job_resrcs->memory_allocated) ||
122 (job_resrcs->memory_allocated &&
123 (last_mem_alloc !=
124 job_resrcs->memory_allocated[rel_node_inx]))) {
125 if (slurm_hostlist_count(hl_last)) {
126 last_hosts =
127 slurm_hostlist_ranged_string_xmalloc(
128 hl_last);
129 nr_hv = newHV();
130 hv_store_charp(nr_hv, "nodes", last_hosts);
131 hv_store_charp(nr_hv, "cpu_ids", tmp2);
132 hv_store_uint64_t(nr_hv, "mem",
133 last_mem_alloc_ptr ?
134 last_mem_alloc : 0);
135 av_store(av, cnt++, newRV_noinc((SV*)nr_hv));
136 xfree(last_hosts);
137 slurm_hostlist_destroy(hl_last);
138 hl_last = slurm_hostlist_create(NULL);
139 }
140 strcpy(tmp2, tmp1);
141 last_mem_alloc_ptr = job_resrcs->memory_allocated;
142 if (last_mem_alloc_ptr)
143 last_mem_alloc = job_resrcs->
144 memory_allocated[rel_node_inx];
145 else
146 last_mem_alloc = NO_VAL64;
147 }
148 slurm_hostlist_push_host(hl_last, host);
149 free(host);
150
151 if (bit_inx > last)
152 break;
153
154 if (abs_node_inx > job_info->node_inx[i+1]) {
155 i += 2;
156 abs_node_inx = job_info->node_inx[i];
157 } else {
158 abs_node_inx++;
159 }
160 }
161
162 if (slurm_hostlist_count(hl_last)) {
163 last_hosts = slurm_hostlist_ranged_string_xmalloc(hl_last);
164 nr_hv = newHV();
165 hv_store_charp(nr_hv, "nodes", last_hosts);
166 hv_store_charp(nr_hv, "cpu_ids", tmp2);
167 hv_store_uint64_t(nr_hv, "mem",
168 last_mem_alloc_ptr ?
169 last_mem_alloc : 0);
170 av_store(av, cnt++, newRV_noinc((SV*)nr_hv));
171 xfree(last_hosts);
172 }
173 slurm_hostlist_destroy(hl);
174 slurm_hostlist_destroy(hl_last);
175 hv_store_sv(hv, "node_resrcs", newRV_noinc((SV*)av));
176
177 return 0;
178 }
179
180 /*
181 * convert job_info_t to perl HV
182 */
183 int
job_info_to_hv(job_info_t * job_info,HV * hv)184 job_info_to_hv(job_info_t *job_info, HV *hv)
185 {
186 int j;
187 AV *av;
188
189 if(job_info->account)
190 STORE_FIELD(hv, job_info, account, charp);
191 if(job_info->alloc_node)
192 STORE_FIELD(hv, job_info, alloc_node, charp);
193 STORE_FIELD(hv, job_info, alloc_sid, uint32_t);
194 STORE_FIELD(hv, job_info, array_job_id, uint32_t);
195 STORE_FIELD(hv, job_info, array_task_id, uint32_t);
196 if(job_info->array_task_str)
197 STORE_FIELD(hv, job_info, array_task_str, charp);
198 STORE_FIELD(hv, job_info, assoc_id, uint32_t);
199 STORE_FIELD(hv, job_info, batch_flag, uint16_t);
200 if(job_info->command)
201 STORE_FIELD(hv, job_info, command, charp);
202 if(job_info->comment)
203 STORE_FIELD(hv, job_info, comment, charp);
204 STORE_FIELD(hv, job_info, contiguous, uint16_t);
205 STORE_FIELD(hv, job_info, cpus_per_task, uint16_t);
206 if(job_info->dependency)
207 STORE_FIELD(hv, job_info, dependency, charp);
208 STORE_FIELD(hv, job_info, derived_ec, uint32_t);
209 STORE_FIELD(hv, job_info, eligible_time, time_t);
210 STORE_FIELD(hv, job_info, end_time, time_t);
211 if(job_info->exc_nodes)
212 STORE_FIELD(hv, job_info, exc_nodes, charp);
213 av = newAV();
214 for(j = 0; ; j += 2) {
215 if(job_info->exc_node_inx[j] == -1)
216 break;
217 av_store(av, j, newSVuv(job_info->exc_node_inx[j]));
218 av_store(av, j+1, newSVuv(job_info->exc_node_inx[j+1]));
219 }
220 hv_store_sv(hv, "exc_node_inx", newRV_noinc((SV*)av));
221
222 STORE_FIELD(hv, job_info, exit_code, uint32_t);
223 if (job_info->features)
224 STORE_FIELD(hv, job_info, features, charp);
225 if (job_info->tres_per_node)
226 STORE_FIELD(hv, job_info, tres_per_node, charp);
227 STORE_FIELD(hv, job_info, group_id, uint32_t);
228 STORE_FIELD(hv, job_info, job_id, uint32_t);
229 STORE_FIELD(hv, job_info, job_state, uint32_t);
230 if(job_info->licenses)
231 STORE_FIELD(hv, job_info, licenses, charp);
232 STORE_FIELD(hv, job_info, max_cpus, uint32_t);
233 STORE_FIELD(hv, job_info, max_nodes, uint32_t);
234 STORE_FIELD(hv, job_info, profile, uint32_t);
235 STORE_FIELD(hv, job_info, sockets_per_node, uint16_t);
236 STORE_FIELD(hv, job_info, cores_per_socket, uint16_t);
237 STORE_FIELD(hv, job_info, threads_per_core, uint16_t);
238 if(job_info->name)
239 STORE_FIELD(hv, job_info, name, charp);
240 if(job_info->network)
241 STORE_FIELD(hv, job_info, network, charp);
242 STORE_FIELD(hv, job_info, nice, uint32_t);
243 if(job_info->nodes)
244 STORE_FIELD(hv, job_info, nodes, charp);
245 if(job_info->sched_nodes)
246 STORE_FIELD(hv, job_info, sched_nodes, charp);
247 av = newAV();
248 for(j = 0; ; j += 2) {
249 if(job_info->node_inx[j] == -1)
250 break;
251 av_store(av, j, newSVuv(job_info->node_inx[j]));
252 av_store(av, j+1, newSVuv(job_info->node_inx[j+1]));
253 }
254 hv_store_sv(hv, "node_inx", newRV_noinc((SV*)av));
255 STORE_FIELD(hv, job_info, ntasks_per_core, uint16_t);
256 STORE_FIELD(hv, job_info, ntasks_per_node, uint16_t);
257 STORE_FIELD(hv, job_info, ntasks_per_socket, uint16_t);
258 STORE_FIELD(hv, job_info, num_nodes, uint32_t);
259 STORE_FIELD(hv, job_info, num_cpus, uint32_t);
260 STORE_FIELD(hv, job_info, pn_min_memory, uint64_t);
261 STORE_FIELD(hv, job_info, pn_min_cpus, uint16_t);
262 STORE_FIELD(hv, job_info, pn_min_tmp_disk, uint32_t);
263
264 if(job_info->partition)
265 STORE_FIELD(hv, job_info, partition, charp);
266 STORE_FIELD(hv, job_info, pre_sus_time, time_t);
267 STORE_FIELD(hv, job_info, priority, uint32_t);
268 if(job_info->qos)
269 STORE_FIELD(hv, job_info, qos, charp);
270 if(job_info->req_nodes)
271 STORE_FIELD(hv, job_info, req_nodes, charp);
272 av = newAV();
273 for(j = 0; ; j += 2) {
274 if(job_info->req_node_inx[j] == -1)
275 break;
276 av_store(av, j, newSVuv(job_info->req_node_inx[j]));
277 av_store(av, j+1, newSVuv(job_info->req_node_inx[j+1]));
278 }
279 hv_store_sv(hv, "req_node_inx", newRV_noinc((SV*)av));
280 STORE_FIELD(hv, job_info, req_switch, uint32_t);
281 STORE_FIELD(hv, job_info, requeue, uint16_t);
282 STORE_FIELD(hv, job_info, resize_time, time_t);
283 STORE_FIELD(hv, job_info, restart_cnt, uint16_t);
284 if(job_info->resv_name)
285 STORE_FIELD(hv, job_info, resv_name, charp);
286 STORE_PTR_FIELD(hv, job_info, select_jobinfo, "Slurm::dynamic_plugin_data_t");
287 STORE_PTR_FIELD(hv, job_info, job_resrcs, "Slurm::job_resources_t");
288 STORE_FIELD(hv, job_info, shared, uint16_t);
289 STORE_FIELD(hv, job_info, show_flags, uint16_t);
290 STORE_FIELD(hv, job_info, start_time, time_t);
291 if(job_info->state_desc)
292 STORE_FIELD(hv, job_info, state_desc, charp);
293 STORE_FIELD(hv, job_info, state_reason, uint16_t);
294 if(job_info->std_in)
295 STORE_FIELD(hv, job_info, std_in, charp);
296 if(job_info->std_out)
297 STORE_FIELD(hv, job_info, std_out, charp);
298 if(job_info->std_err)
299 STORE_FIELD(hv, job_info, std_err, charp);
300 STORE_FIELD(hv, job_info, submit_time, time_t);
301 STORE_FIELD(hv, job_info, suspend_time, time_t);
302 STORE_FIELD(hv, job_info, time_limit, uint32_t);
303 STORE_FIELD(hv, job_info, time_min, uint32_t);
304 STORE_FIELD(hv, job_info, user_id, uint32_t);
305 STORE_FIELD(hv, job_info, wait4switch, uint32_t);
306 if(job_info->wckey)
307 STORE_FIELD(hv, job_info, wckey, charp);
308 if(job_info->work_dir)
309 STORE_FIELD(hv, job_info, work_dir, charp);
310
311 _job_resrcs_to_hv(job_info, hv);
312
313 return 0;
314 }
315
316 /*
317 * convert perl HV to job_info_t
318 */
319 int
hv_to_job_info(HV * hv,job_info_t * job_info)320 hv_to_job_info(HV *hv, job_info_t *job_info)
321 {
322 SV **svp;
323 AV *av;
324 int i, n;
325
326 memset(job_info, 0, sizeof(job_info_t));
327
328 FETCH_FIELD(hv, job_info, account, charp, FALSE);
329 FETCH_FIELD(hv, job_info, alloc_node, charp, FALSE);
330 FETCH_FIELD(hv, job_info, alloc_sid, uint32_t, TRUE);
331 FETCH_FIELD(hv, job_info, array_job_id, uint32_t, TRUE);
332 FETCH_FIELD(hv, job_info, array_task_id, uint32_t, TRUE);
333 FETCH_FIELD(hv, job_info, array_task_str, charp, FALSE);
334 FETCH_FIELD(hv, job_info, batch_flag, uint16_t, TRUE);
335 FETCH_FIELD(hv, job_info, command, charp, FALSE);
336 FETCH_FIELD(hv, job_info, comment, charp, FALSE);
337 FETCH_FIELD(hv, job_info, contiguous, uint16_t, TRUE);
338 FETCH_FIELD(hv, job_info, cpus_per_task, uint16_t, TRUE);
339 FETCH_FIELD(hv, job_info, dependency, charp, FALSE);
340 FETCH_FIELD(hv, job_info, derived_ec, uint32_t, TRUE);
341 FETCH_FIELD(hv, job_info, eligible_time, time_t, TRUE);
342 FETCH_FIELD(hv, job_info, end_time, time_t, TRUE);
343 FETCH_FIELD(hv, job_info, exc_nodes, charp, FALSE);
344 svp = hv_fetch(hv, "exc_node_inx", 12, FALSE);
345 if (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVAV) {
346 av = (AV*)SvRV(*svp);
347 n = av_len(av) + 2; /* for trailing -1 */
348 job_info->exc_node_inx = xmalloc(n * sizeof(int));
349 for (i = 0; i < n-1; i += 2) {
350 job_info->exc_node_inx[i] = (int)SvIV(*(av_fetch(av, i, FALSE)));
351 job_info->exc_node_inx[i+1] = (int)SvIV(*(av_fetch(av, i+1, FALSE)));
352 }
353 job_info->exc_node_inx[n-1] = -1;
354 } else {
355 /* nothing to do */
356 }
357 FETCH_FIELD(hv, job_info, exit_code, uint32_t, TRUE);
358 FETCH_FIELD(hv, job_info, features, charp, FALSE);
359 FETCH_FIELD(hv, job_info, tres_per_node, charp, FALSE);
360 FETCH_FIELD(hv, job_info, group_id, uint32_t, TRUE);
361 FETCH_FIELD(hv, job_info, job_id, uint32_t, TRUE);
362 FETCH_FIELD(hv, job_info, job_state, uint32_t, TRUE);
363 FETCH_FIELD(hv, job_info, licenses, charp, FALSE);
364 FETCH_FIELD(hv, job_info, max_cpus, uint32_t, TRUE);
365 FETCH_FIELD(hv, job_info, max_nodes, uint32_t, TRUE);
366 FETCH_FIELD(hv, job_info, profile, uint32_t, TRUE);
367 FETCH_FIELD(hv, job_info, sockets_per_node, uint16_t, TRUE);
368 FETCH_FIELD(hv, job_info, cores_per_socket, uint16_t, TRUE);
369 FETCH_FIELD(hv, job_info, threads_per_core, uint16_t, TRUE);
370 FETCH_FIELD(hv, job_info, name, charp, FALSE);
371 FETCH_FIELD(hv, job_info, network, charp, FALSE);
372 FETCH_FIELD(hv, job_info, nice, uint32_t, TRUE);
373 FETCH_FIELD(hv, job_info, nodes, charp, FALSE);
374 FETCH_FIELD(hv, job_info, sched_nodes, charp, FALSE);
375 svp = hv_fetch(hv, "node_inx", 8, FALSE);
376 if (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVAV) {
377 av = (AV*)SvRV(*svp);
378 n = av_len(av) + 2; /* for trailing -1 */
379 job_info->node_inx = xmalloc(n * sizeof(int));
380 for (i = 0; i < n-1; i += 2) {
381 job_info->node_inx[i] = (int)SvIV(*(av_fetch(av, i, FALSE)));
382 job_info->node_inx[i+1] = (int)SvIV(*(av_fetch(av, i+1, FALSE)));
383 }
384 job_info->node_inx[n-1] = -1;
385 } else {
386 /* nothing to do */
387 }
388 FETCH_FIELD(hv, job_info, ntasks_per_core, uint16_t, TRUE);
389 FETCH_FIELD(hv, job_info, ntasks_per_node, uint16_t, TRUE);
390 FETCH_FIELD(hv, job_info, ntasks_per_socket, uint16_t, TRUE);
391 FETCH_FIELD(hv, job_info, num_nodes, uint32_t, TRUE);
392 FETCH_FIELD(hv, job_info, num_cpus, uint32_t, TRUE);
393 FETCH_FIELD(hv, job_info, pn_min_memory, uint64_t, TRUE);
394 FETCH_FIELD(hv, job_info, pn_min_cpus, uint16_t, TRUE);
395 FETCH_FIELD(hv, job_info, pn_min_tmp_disk, uint32_t, TRUE);
396 FETCH_FIELD(hv, job_info, partition, charp, FALSE);
397 FETCH_FIELD(hv, job_info, pre_sus_time, time_t, TRUE);
398 FETCH_FIELD(hv, job_info, priority, uint32_t, TRUE);
399 FETCH_FIELD(hv, job_info, qos, charp, FALSE);
400 FETCH_FIELD(hv, job_info, req_nodes, charp, FALSE);
401 svp = hv_fetch(hv, "req_node_inx", 12, FALSE);
402 if (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVAV) {
403 av = (AV*)SvRV(*svp);
404 n = av_len(av) + 2; /* for trailing -1 */
405 job_info->req_node_inx = xmalloc(n * sizeof(int));
406 for (i = 0; i < n-1; i += 2) {
407 job_info->req_node_inx[i] = (int)SvIV(*(av_fetch(av, i, FALSE)));
408 job_info->req_node_inx[i+1] = (int)SvIV(*(av_fetch(av, i+1, FALSE)));
409 }
410 job_info->req_node_inx[n-1] = -1;
411 } else {
412 /* nothing to do */
413 }
414 FETCH_FIELD(hv, job_info, req_switch, uint32_t, FALSE);
415 FETCH_FIELD(hv, job_info, requeue, uint16_t, TRUE);
416 FETCH_FIELD(hv, job_info, resize_time, time_t, TRUE);
417 FETCH_FIELD(hv, job_info, restart_cnt, uint16_t, TRUE);
418 FETCH_FIELD(hv, job_info, resv_name, charp, FALSE);
419 FETCH_PTR_FIELD(hv, job_info, select_jobinfo, "Slurm::dynamic_plugin_data_t", FALSE);
420 FETCH_PTR_FIELD(hv, job_info, job_resrcs, "Slurm::job_resources_t", FALSE);
421 FETCH_FIELD(hv, job_info, shared, uint16_t, TRUE);
422 FETCH_FIELD(hv, job_info, show_flags, uint16_t, TRUE);
423 FETCH_FIELD(hv, job_info, start_time, time_t, TRUE);
424 FETCH_FIELD(hv, job_info, state_desc, charp, FALSE);
425 FETCH_FIELD(hv, job_info, state_reason, uint16_t, TRUE);
426 FETCH_FIELD(hv, job_info, std_in, charp, FALSE);
427 FETCH_FIELD(hv, job_info, std_out, charp, FALSE);
428 FETCH_FIELD(hv, job_info, std_err, charp, FALSE);
429 FETCH_FIELD(hv, job_info, submit_time, time_t, TRUE);
430 FETCH_FIELD(hv, job_info, suspend_time, time_t, TRUE);
431 FETCH_FIELD(hv, job_info, time_limit, uint32_t, TRUE);
432 FETCH_FIELD(hv, job_info, time_min, uint32_t, TRUE);
433 FETCH_FIELD(hv, job_info, user_id, uint32_t, TRUE);
434 FETCH_FIELD(hv, job_info, wait4switch, uint32_t, FALSE);
435 FETCH_FIELD(hv, job_info, wckey, charp, FALSE);
436 FETCH_FIELD(hv, job_info, work_dir, charp, FALSE);
437 return 0;
438 }
439
440 /*
441 * convert job_info_msg_t to perl HV
442 */
443 int
job_info_msg_to_hv(job_info_msg_t * job_info_msg,HV * hv)444 job_info_msg_to_hv(job_info_msg_t *job_info_msg, HV *hv)
445 {
446 int i;
447 HV *hv_info;
448 AV *av;
449
450 _load_node_info();
451
452 STORE_FIELD(hv, job_info_msg, last_update, time_t);
453 /* record_count implied in job_array */
454 av = newAV();
455 for(i = 0; i < job_info_msg->record_count; i ++) {
456 hv_info = newHV();
457 if (job_info_to_hv(job_info_msg->job_array + i, hv_info) < 0) {
458 SvREFCNT_dec(hv_info);
459 SvREFCNT_dec(av);
460 return -1;
461 }
462 av_store(av, i, newRV_noinc((SV*)hv_info));
463 }
464 hv_store_sv(hv, "job_array", newRV_noinc((SV*)av));
465
466 _free_node_info();
467
468 return 0;
469 }
470
471 /*
472 * convert perl HV to job_info_msg_t
473 */
474 int
hv_to_job_info_msg(HV * hv,job_info_msg_t * job_info_msg)475 hv_to_job_info_msg(HV *hv, job_info_msg_t *job_info_msg)
476 {
477 SV **svp;
478 AV *av;
479 int i, n;
480
481 memset(job_info_msg, 0, sizeof(job_info_msg_t));
482
483 FETCH_FIELD(hv, job_info_msg, last_update, time_t, TRUE);
484 svp = hv_fetch(hv, "job_array", 9, FALSE);
485 if (! (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVAV)) {
486 Perl_warn (aTHX_ "job_array is not an array reference in HV for job_info_msg_t");
487 return -1;
488 }
489 av = (AV*)SvRV(*svp);
490 n = av_len(av) + 1;
491 job_info_msg->record_count = n;
492
493 job_info_msg->job_array = xmalloc(n * sizeof(job_info_t));
494 for(i = 0; i < n; i ++) {
495 svp = av_fetch(av, i, FALSE);
496 if (! (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVHV)) {
497 Perl_warn (aTHX_ "element %d in job_array is not valid", i);
498 return -1;
499 }
500 if (hv_to_job_info((HV*)SvRV(*svp), &job_info_msg->job_array[i]) < 0) {
501 Perl_warn(aTHX_ "failed to convert element %d in job_array", i);
502 return -1;
503 }
504 }
505 return 0;
506 }
507