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