1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4 #define NEED_newRV_noinc_GLOBAL
5 #include "ppport.h"
6 
7 #include <slurm/slurm.h>
8 #include <signal.h>
9 #include <string.h>
10 #include <unistd.h>
11 
12 #include "slurm-perl.h"
13 #include "bitstr.h"
14 
15 extern void slurm_conf_init(char *pathname);
16 
17 /* Custom typemap that free's memory after copying to perl stack. */
18 typedef char char_xfree;
19 typedef char char_free;
20 
21 struct slurm {
22 };
23 typedef struct slurm * slurm_t;
24 
25 /*
26  * default slurm object, for backward compatibility with "Slurm->method()".
27  */
28 static struct slurm default_slurm_object;
29 
30 static slurm_t
new_slurm(void)31 new_slurm(void)
32 {
33 	int size = sizeof(struct slurm);
34 	if (size == 0) {
35 		/* Avoid returning NULL, which causes the perl APIs to fail */
36 		size = 1;
37 	}
38 	return xmalloc(size);
39 }
40 
41 static void
free_slurm(slurm_t self)42 free_slurm(slurm_t self)
43 {
44 	xfree(self);
45 }
46 
47 
48 
49 /********************************************************************/
50 
51 MODULE = Slurm		PACKAGE = Slurm		PREFIX=slurm_
52 PROTOTYPES: ENABLE
53 
54 BOOT:
55 {
56 	slurm_conf_init(NULL);
57 }
58 
59 ######################################################################
60 # 	CONSTRUCTOR/DESTRUCTOR FUNCTIONS
61 ######################################################################
62 
63 #
64 # $slurm = Slurm::new($conf_file);
65 #
66 slurm_t
67 slurm_new(char *conf_file=NULL)
68 	CODE:
69 		slurm_conf_init(conf_file);
70 		RETVAL = new_slurm();
71 		if (RETVAL == NULL) {
72 			XSRETURN_UNDEF;
73 		}
74 	OUTPUT:
75 		RETVAL
76 
77 void
78 slurm_DESTROY(slurm_t self)
79 	CODE:
80 		if (self != &default_slurm_object) {
81 			free_slurm(self);
82 		}
83 
84 ######################################################################
85 # 	ERROR INFORMATION FUNCTIONS
86 ######################################################################
87 
88 int
89 slurm_get_errno(slurm_t self)
90 	C_ARGS:
91 	INIT:
92 		if (self); /* this is needed to avoid a warning about
93 			      unused variables.  But if we take slurm_t self
94 			      out of the mix Slurm-> doesn't work,
95 			      only Slurm::
96 			    */
97 
98 char *
99 slurm_strerror(slurm_t self, int errnum=0)
100 	CODE:
101 		if (self); /* this is needed to avoid a warning about
102 			      unused variables.  But if we take slurm_t self
103 			      out of the mix Slurm-> doesn't work,
104 			      only Slurm::
105 			    */
106 		if (errnum == 0)
107 			errnum = slurm_get_errno();
108 		RETVAL = slurm_strerror(errnum);
109 	OUTPUT:
110 		RETVAL
111 
112 
113 ######################################################################
114 # 	ENTITY STATE/REASON/FLAG/TYPE STRING FUNCTIONS
115 ######################################################################
116 #
117 # These functions are made object method instead of class method.
118 
119 char *
120 slurm_preempt_mode_string(slurm_t self, uint16_t preempt_mode);
121 	CODE:
122 		if (self); /* this is needed to avoid a warning about
123 			      unused variables.  But if we take slurm_t self
124 			      out of the mix Slurm-> doesn't work,
125 			      only Slurm::
126 			    */
127 		RETVAL = slurm_preempt_mode_string(preempt_mode);
128 	OUTPUT:
129 		RETVAL
130 
131 uint16_t
132 slurm_preempt_mode_num(slurm_t self, char *preempt_mode)
133 	C_ARGS:
134 		preempt_mode
135 	INIT:
136 		if (self); /* this is needed to avoid a warning about
137 			      unused variables.  But if we take slurm_t self
138 			      out of the mix Slurm-> doesn't work,
139 			      only Slurm::
140 			    */
141 
142 char *
143 slurm_job_reason_string(slurm_t self, uint32_t inx)
144 	CODE:
145 		if (self); /* this is needed to avoid a warning about
146 			      unused variables.  But if we take slurm_t self
147 			      out of the mix Slurm-> doesn't work,
148 			      only Slurm::
149 			    */
150 		RETVAL = slurm_job_reason_string(inx);
151 	OUTPUT:
152 		RETVAL
153 
154 char *
155 slurm_job_state_string(slurm_t self, uint32_t inx)
156 	CODE:
157 		if (self); /* this is needed to avoid a warning about
158 			      unused variables.  But if we take slurm_t self
159 			      out of the mix Slurm-> doesn't work,
160 			      only Slurm::
161 			    */
162 		RETVAL = slurm_job_state_string(inx);
163 	OUTPUT:
164 		RETVAL
165 
166 char *
167 slurm_job_state_string_compact(slurm_t self, uint32_t inx)
168 	CODE:
169 		if (self); /* this is needed to avoid a warning about
170 			      unused variables.  But if we take slurm_t self
171 			      out of the mix Slurm-> doesn't work,
172 			      only Slurm::
173 			    */
174 		RETVAL = slurm_job_state_string_compact(inx);
175 	OUTPUT:
176 		RETVAL
177 
178 int
179 slurm_job_state_num(slurm_t self, char *state_name)
180 	C_ARGS:
181 		state_name
182 	INIT:
183 		if (self); /* this is needed to avoid a warning about
184 			      unused variables.  But if we take slurm_t self
185 			      out of the mix Slurm-> doesn't work,
186 			      only Slurm::
187 			    */
188 
189 char_xfree *
190 slurm_reservation_flags_string(slurm_t self, uint16_t flags)
191 	CODE:
192 		if (self); /* this is needed to avoid a warning about
193 			      unused variables.  But if we take slurm_t self
194 			      out of the mix Slurm-> doesn't work,
195 			      only Slurm::
196 			    */
197 		RETVAL = slurm_reservation_flags_string(flags);
198 	OUTPUT:
199 		RETVAL
200 
201 char *
202 slurm_node_state_string(slurm_t self, uint32_t inx)
203 	CODE:
204 		if (self); /* this is needed to avoid a warning about
205 			      unused variables.  But if we take slurm_t self
206 			      out of the mix Slurm-> doesn't work,
207 			      only Slurm::
208 			    */
209 		RETVAL = slurm_node_state_string(inx);
210 	OUTPUT:
211 		RETVAL
212 
213 char *
214 slurm_node_state_string_compact(slurm_t self, uint32_t inx)
215 	CODE:
216 		if (self); /* this is needed to avoid a warning about
217 			      unused variables.  But if we take slurm_t self
218 			      out of the mix Slurm-> doesn't work,
219 			      only Slurm::
220 			    */
221 		RETVAL = slurm_node_state_string_compact(inx);
222 	OUTPUT:
223 		RETVAL
224 
225 char *
226 slurm_private_data_string(slurm_t self, uint16_t private_data)
227 	PREINIT:
228 		char tmp_str[128];
229 	CODE:
230 		if (self); /* this is needed to avoid a warning about
231 			      unused variables.  But if we take slurm_t self
232 			      out of the mix Slurm-> doesn't work,
233 			      only Slurm::
234 			    */
235 		slurm_private_data_string(private_data, tmp_str, sizeof(tmp_str));
236 		RETVAL = tmp_str;
237 	OUTPUT:
238 		RETVAL
239 
240 char *
241 slurm_accounting_enforce_string(slurm_t self, uint16_t enforce)
242 	PREINIT:
243 		char tmp_str[128];
244 	CODE:
245 		if (self); /* this is needed to avoid a warning about
246 			      unused variables.  But if we take slurm_t self
247 			      out of the mix Slurm-> doesn't work,
248 			      only Slurm::
249 			    */
250 		slurm_accounting_enforce_string(enforce, tmp_str, sizeof(tmp_str));
251 		RETVAL = tmp_str;
252 	OUTPUT:
253 		RETVAL
254 
255 ######################################################################
256 # 	RESOURCE ALLOCATION FUNCTIONS
257 ######################################################################
258 
259 #
260 # $resp = $slurm->allocate_resources($desc);
261 HV *
262 slurm_allocate_resources(slurm_t self, HV *job_desc)
263 	PREINIT:
264 		job_desc_msg_t jd_msg;
265 		resource_allocation_response_msg_t* resp_msg = NULL;
266 		int rc;
267 	CODE:
268 		if (self); /* this is needed to avoid a warning about
269 			      unused variables.  But if we take slurm_t self
270 			      out of the mix Slurm-> doesn't work,
271 			      only Slurm::
272 			    */
273 		if (hv_to_job_desc_msg(job_desc, &jd_msg) < 0) {
274 			XSRETURN_UNDEF;
275 		}
276 		rc = slurm_allocate_resources(&jd_msg, &resp_msg);
277 		free_job_desc_msg_memory(&jd_msg);
278 		if (resp_msg == NULL) {
279 			XSRETURN_UNDEF;
280 		}
281 		if(rc != SLURM_SUCCESS) {
282 			slurm_free_resource_allocation_response_msg(resp_msg);
283 			XSRETURN_UNDEF;
284 		}
285 		RETVAL = newHV();
286 		sv_2mortal((SV*)RETVAL);
287 		rc = resource_allocation_response_msg_to_hv(resp_msg, RETVAL);
288 		slurm_free_resource_allocation_response_msg(resp_msg);
289 		if (rc < 0) {
290 			XSRETURN_UNDEF;
291 		}
292 	OUTPUT:
293 		RETVAL
294 
295 HV *
296 slurm_allocate_resources_blocking(slurm_t self, HV *user_req, time_t timeout=0, SV *pending_callback=NULL)
297 	PREINIT:
298 		job_desc_msg_t jd_msg;
299 		resource_allocation_response_msg_t *resp_msg = NULL;
300 	CODE:
301 		if (self); /* this is needed to avoid a warning about
302 			      unused variables.  But if we take slurm_t self
303 			      out of the mix Slurm-> doesn't work,
304 			      only Slurm::
305 			    */
306 		if (hv_to_job_desc_msg(user_req, &jd_msg) < 0) {
307 			XSRETURN_UNDEF;
308 		}
309 		set_sarb_cb(pending_callback);
310 		resp_msg = slurm_allocate_resources_blocking(&jd_msg, timeout,
311 				pending_callback == NULL ? NULL : sarb_cb);
312 		free_job_desc_msg_memory(&jd_msg);
313 		if (resp_msg != NULL) {
314 			RETVAL = newHV();
315 			sv_2mortal((SV*)RETVAL);
316 			resource_allocation_response_msg_to_hv(resp_msg, RETVAL);
317 			slurm_free_resource_allocation_response_msg(resp_msg);
318 		}
319 		else {
320 			XSRETURN_UNDEF;
321 		}
322 	OUTPUT:
323 		RETVAL
324 
325 
326 HV *
327 slurm_allocation_lookup(slurm_t self, uint32_t job_id)
328 	PREINIT:
329 		resource_allocation_response_msg_t *resp_msg = NULL;
330 		int rc;
331 	CODE:
332 		if (self); /* this is needed to avoid a warning about
333 			      unused variables.  But if we take slurm_t self
334 			      out of the mix Slurm-> doesn't work,
335 			      only Slurm::
336 			    */
337 		rc = slurm_allocation_lookup(job_id, &resp_msg);
338 		if(rc != SLURM_SUCCESS) {
339 			slurm_free_resource_allocation_response_msg(resp_msg);
340 			XSRETURN_UNDEF;
341 		}
342 		RETVAL = newHV();
343 		sv_2mortal((SV*)RETVAL);
344 		rc = resource_allocation_response_msg_to_hv(resp_msg, RETVAL);
345 		slurm_free_resource_allocation_response_msg(resp_msg);
346 		if (rc < 0) {
347 			XSRETURN_UNDEF;
348 		}
349 	OUTPUT:
350 		RETVAL
351 
352 char_free *
353 slurm_read_hostfile(slurm_t self, char *filename, int n)
354 	CODE:
355 		if (self); /* this is needed to avoid a warning about
356 			      unused variables.  But if we take slurm_t self
357 			      out of the mix Slurm-> doesn't work,
358 			      only Slurm::
359 			    */
360 		RETVAL = slurm_read_hostfile(filename, n);
361 		if(RETVAL == NULL) {
362 			XSRETURN_UNDEF;
363 		}
364 	OUTPUT:
365 		RETVAL
366 
367 allocation_msg_thread_t *
368 slurm_allocation_msg_thr_create(slurm_t self, OUT uint16_t port, HV *callbacks)
369 	INIT:
370 		if (self); /* this is needed to avoid a warning about
371 			      unused variables.  But if we take slurm_t self
372 			      out of the mix Slurm-> doesn't work,
373 			      only Slurm::
374 			    */
375 		set_sacb(callbacks);
376 	C_ARGS:
377 		&port, &sacb
378 
379 void
380 slurm_allocation_msg_thr_destroy(slurm_t self, allocation_msg_thread_t * msg_thr)
381 	INIT:
382 		if (self); /* this is needed to avoid a warning about
383 			      unused variables.  But if we take slurm_t self
384 			      out of the mix Slurm-> doesn't work,
385 			      only Slurm::
386 			    */
387 
388 	C_ARGS:
389 		msg_thr
390 
391 HV *
392 slurm_submit_batch_job(slurm_t self, HV *job_desc)
393 	PREINIT:
394 		job_desc_msg_t jd_msg;
395 		submit_response_msg_t *resp_msg = NULL;
396 		int rc;
397 	CODE:
398 		if (self); /* this is needed to avoid a warning about
399 			      unused variables.  But if we take slurm_t self
400 			      out of the mix Slurm-> doesn't work,
401 			      only Slurm::
402 			    */
403 		if(hv_to_job_desc_msg(job_desc, &jd_msg) < 0) {
404 			XSRETURN_UNDEF;
405 		}
406 		rc = slurm_submit_batch_job(&jd_msg, &resp_msg);
407 		free_job_desc_msg_memory(&jd_msg);
408 		if(rc != SLURM_SUCCESS) {
409 			slurm_free_submit_response_response_msg(resp_msg);
410 			XSRETURN_UNDEF;
411 		}
412 		RETVAL = newHV();
413 		sv_2mortal((SV*)RETVAL);
414 		rc = submit_response_msg_to_hv(resp_msg, RETVAL);
415 		slurm_free_submit_response_response_msg(resp_msg);
416 		if (rc < 0) {
417 			XSRETURN_UNDEF;
418 		}
419 	OUTPUT:
420 		RETVAL
421 
422 int
423 slurm_job_will_run(slurm_t self, HV *job_desc)
424 	PREINIT:
425 		job_desc_msg_t jd_msg;
426 	CODE:
427 		if (self); /* this is needed to avoid a warning about
428 			      unused variables.  But if we take slurm_t self
429 			      out of the mix Slurm-> doesn't work,
430 			      only Slurm::
431 			    */
432 		if (hv_to_job_desc_msg(job_desc, &jd_msg) < 0) {
433 			XSRETURN_UNDEF;
434 		}
435 		RETVAL = slurm_job_will_run(&jd_msg);
436 		free_job_desc_msg_memory(&jd_msg);
437 	OUTPUT:
438 		RETVAL
439 
440 HV *
441 slurm_sbcast_lookup(slurm_t self, uint32_t job_id, uint32_t step_id)
442 	PREINIT:
443 		job_sbcast_cred_msg_t *info;
444 		int rc;
445 		uint32_t het_job_offset = NO_VAL;
446 	CODE:
447 		if (self); /* this is needed to avoid a warning about
448 			      unused variables.  But if we take slurm_t self
449 			      out of the mix Slurm-> doesn't work,
450 			      only Slurm::
451 			    */
452 		rc = slurm_sbcast_lookup(job_id, het_job_offset, step_id,
453 					 &info);
454 		if (rc == SLURM_SUCCESS) {
455 			RETVAL = newHV();
456 			sv_2mortal((SV*)RETVAL);
457 			rc = job_sbcast_cred_msg_to_hv(info, RETVAL);
458 			slurm_free_sbcast_cred_msg(info);
459 			if (rc < 0) {
460 				XSRETURN_UNDEF;
461 			}
462 		} else {
463 			XSRETURN_UNDEF;
464 		}
465 	OUTPUT:
466 		RETVAL
467 
468 
469 ######################################################################
470 #	JOB/STEP SIGNALING FUNCTIONS
471 ######################################################################
472 int
473 slurm_kill_job(slurm_t self, uint32_t job_id, uint16_t signal, uint16_t batch_flag=0)
474 	INIT:
475 		if (self); /* this is needed to avoid a warning about
476 			      unused variables.  But if we take slurm_t self
477 			      out of the mix Slurm-> doesn't work,
478 			      only Slurm::
479 			    */
480 	C_ARGS:
481 		job_id, signal, batch_flag
482 
483 int
484 slurm_kill_job_step(slurm_t self, uint32_t job_id, uint32_t step_id, uint16_t signal)
485 	INIT:
486 		if (self); /* this is needed to avoid a warning about
487 			      unused variables.  But if we take slurm_t self
488 			      out of the mix Slurm-> doesn't work,
489 			      only Slurm::
490 			    */
491 	C_ARGS:
492 		job_id, step_id, signal
493 
494 int
495 slurm_signal_job(slurm_t self, uint32_t job_id, uint16_t signal)
496 	INIT:
497 		if (self); /* this is needed to avoid a warning about
498 			      unused variables.  But if we take slurm_t self
499 			      out of the mix Slurm-> doesn't work,
500 			      only Slurm::
501 			    */
502 	C_ARGS:
503 		job_id, signal
504 
505 int
506 slurm_signal_job_step(slurm_t self, uint32_t job_id, uint32_t step_id, uint16_t signal)
507 	INIT:
508 		if (self); /* this is needed to avoid a warning about
509 			      unused variables.  But if we take slurm_t self
510 			      out of the mix Slurm-> doesn't work,
511 			      only Slurm::
512 			    */
513 	C_ARGS:
514 		job_id, step_id, signal
515 
516 
517 ######################################################################
518 #	JOB/STEP COMPLETION FUNCTIONS
519 ######################################################################
520 int
521 slurm_complete_job(slurm_t self, uint32_t job_id, uint32_t job_rc=0)
522 	INIT:
523 		if (self); /* this is needed to avoid a warning about
524 			      unused variables.  But if we take slurm_t self
525 			      out of the mix Slurm-> doesn't work,
526 			      only Slurm::
527 			    */
528 	C_ARGS:
529 		job_id, job_rc
530 
531 int
532 slurm_terminate_job_step(slurm_t self, uint32_t job_id, uint32_t step_id)
533 	INIT:
534 		if (self); /* this is needed to avoid a warning about
535 			      unused variables.  But if we take slurm_t self
536 			      out of the mix Slurm-> doesn't work,
537 			      only Slurm::
538 			    */
539 	C_ARGS:
540 		job_id, step_id
541 
542 
543 ######################################################################
544 #       SLURM TASK SPAWNING FUNCTIONS
545 ######################################################################
546 MODULE=Slurm PACKAGE=Slurm PREFIX=slurm_
547 
548 # $ctx = $slurm->step_ctx_create($params);
549 slurm_step_ctx_t *
550 slurm_step_ctx_create(slurm_t self, HV *step_params)
551 	PREINIT:
552 		slurm_step_ctx_params_t sp;
553 	CODE:
554 		if (self); /* this is needed to avoid a warning about
555 			      unused variables.  But if we take slurm_t self
556 			      out of the mix Slurm-> doesn't work,
557 			      only Slurm::
558 			    */
559 		if (hv_to_slurm_step_ctx_params(step_params, &sp) < 0) {
560 			XSRETURN_UNDEF;
561 		}
562 		RETVAL = slurm_step_ctx_create(&sp);
563 		if (RETVAL == NULL) {
564 			XSRETURN_UNDEF;
565 		}
566 	OUTPUT:
567 		RETVAL
568 
569 slurm_step_ctx_t *
570 slurm_step_ctx_create_no_alloc(slurm_t self, HV *step_params, uint32_t step_id)
571 	PREINIT:
572 		slurm_step_ctx_params_t sp;
573 	CODE:
574 		if (self); /* this is needed to avoid a warning about
575 			      unused variables.  But if we take slurm_t self
576 			      out of the mix Slurm-> doesn't work,
577 			      only Slurm::
578 			    */
579 		if (hv_to_slurm_step_ctx_params(step_params, &sp) < 0) {
580 			XSRETURN_UNDEF;
581 		}
582 		RETVAL = slurm_step_ctx_create_no_alloc(&sp, step_id);
583 		if (RETVAL == NULL) {
584 			XSRETURN_UNDEF;
585 		}
586 	OUTPUT:
587 		RETVAL
588 
589 ######################################################################
590 MODULE=Slurm PACKAGE=Slurm::Stepctx PREFIX=slurm_step_ctx_
591 int
592 slurm_step_ctx_get(slurm_step_ctx_t *ctx, int ctx_key, INOUT ...)
593 	PREINIT:
594 		uint32_t tmp_32, *tmp_32_ptr;
595 		uint16_t tmp_16, *tmp_16_ptr;
596 #if 0
597 		/* TODO: job_step_create_response_msg_t not exported in slurm.h */
598 		job_step_create_response_msg_t *resp_msg;
599 #endif
600 		slurm_cred_t *cred;
601 		dynamic_plugin_data_t *switch_info;
602 		char *tmp_str;
603 		int i, tmp_int, *tmp_int_ptr;
604 	CODE:
605 		switch(ctx_key) {
606 		case SLURM_STEP_CTX_JOBID: /* uint32_t* */
607 		case SLURM_STEP_CTX_STEPID: /* uint32_t* */
608 		case SLURM_STEP_CTX_NUM_HOSTS: /* uint32_t* */
609 			if (items != 3) {
610 				Perl_warn( aTHX_ "error number of parameters");
611 				errno = EINVAL;
612 				RETVAL = SLURM_ERROR;
613 				break;
614 			}
615 			RETVAL = slurm_step_ctx_get(ctx, ctx_key, &tmp_32);
616 			if (RETVAL == SLURM_SUCCESS) {
617 				sv_setuv(ST(2), (UV)tmp_32);
618 			}
619 			break;
620 		case SLURM_STEP_CTX_TASKS: /* uint16_t** */
621 			if (items != 3) {
622 				Perl_warn( aTHX_ "error number of parameters");
623 				errno = EINVAL;
624 				RETVAL = SLURM_ERROR;
625 				break;
626 			}
627 			RETVAL = slurm_step_ctx_get(ctx, SLURM_STEP_CTX_NUM_HOSTS, &tmp_32);
628 			if (RETVAL != SLURM_SUCCESS)
629 				break;
630 			RETVAL = slurm_step_ctx_get(ctx, ctx_key, &tmp_16_ptr);
631 			if (RETVAL == SLURM_SUCCESS) {
632 				AV* av = newAV();
633 				for(i = 0; i < tmp_32; i ++) {
634 					av_store_uint16_t(av, i, tmp_16_ptr[i]);
635 				}
636 				sv_setsv(ST(2), newRV_noinc((SV*)av));
637 			}
638 			break;
639 		case SLURM_STEP_CTX_TID: /* uint32_t, uint32_t** */
640 			if (items != 4) {
641 				Perl_warn( aTHX_ "error number of parameters");
642 				errno = EINVAL;
643 				RETVAL = SLURM_ERROR;
644 				break;
645 			}
646 			tmp_32 = (uint32_t)SvUV(ST(2));
647 			RETVAL = slurm_step_ctx_get(ctx, SLURM_STEP_CTX_TASKS, &tmp_16_ptr);
648 			if (RETVAL != SLURM_SUCCESS)
649 				break;
650 			tmp_16 = tmp_16_ptr[tmp_32];
651 			RETVAL = slurm_step_ctx_get(ctx, ctx_key, tmp_32, &tmp_32_ptr);
652 			if (RETVAL == SLURM_SUCCESS) {
653 				AV* av = newAV();
654 				for(i = 0; i < tmp_16; i ++) {
655 					av_store_uint32_t(av, i, tmp_32_ptr[i]);
656 				}
657 				sv_setsv(ST(3), newRV_noinc((SV*)av));
658 			}
659 			break;
660 #if 0
661 		case SLURM_STEP_CTX_RESP: /* job_step_create_response_msg_t** */
662 			if (items != 3) {
663 				Perl_warn( aTHX_ "error number of parameters");
664 				errno = EINVAL;
665 				RETVAL = SLURM_ERROR;
666 				break;
667 			}
668 			RETVAL = slurm_step_ctx_get(ctx, ctx_key, &resp_msg);
669 			if (RETVAL == SLURM_SUCCESS) {
670 				HV *hv = newHV();
671 				if (job_step_create_response_msg_to_hv(resp_msg, hv) < 0) {
672 					SVdev_REFCNT((SV*)hv);
673 					RETVAL = SLURM_ERROR;
674 					break;
675 				}
676 				sv_setsv(ST(2), newRV_noinc((SV*)hv));
677 			}
678 			break;
679 #endif
680 		case SLURM_STEP_CTX_CRED: /* slurm_cred_t** */
681 			if (items != 3) {
682 				Perl_warn( aTHX_ "error number of parameters");
683 				errno = EINVAL;
684 				RETVAL = SLURM_ERROR;
685 				break;
686 			}
687 			RETVAL = slurm_step_ctx_get(ctx, ctx_key, &cred);
688 			if (RETVAL == SLURM_SUCCESS && cred) {
689 				sv_setref_pv(ST(2), "Slurm::slurm_cred_t", (void*)cred);
690 			} else if (RETVAL == SLURM_SUCCESS) {
691 				/* the returned cred is NULL */
692 				sv_setsv(ST(2), &PL_sv_undef);
693 			}
694 			break;
695 		case SLURM_STEP_CTX_SWITCH_JOB: /* switch_jobinfo_t** */
696 			if (items != 3) {
697 				Perl_warn( aTHX_ "error number of parameters");
698 				errno = EINVAL;
699 				RETVAL = SLURM_ERROR;
700 				break;
701 			}
702 			RETVAL = slurm_step_ctx_get(ctx, ctx_key, &switch_info);
703 			if (RETVAL == SLURM_SUCCESS && switch_info) {
704 				sv_setref_pv(ST(2), "Slurm::dynamic_plugin_data_t", (void*)switch_info);
705 			} else if (RETVAL == SLURM_SUCCESS) {
706 				/* the returned switch_info is NULL */
707 				sv_setsv(ST(2), &PL_sv_undef);
708 			}
709 			break;
710 		case SLURM_STEP_CTX_HOST: /* uint32_t, char** */
711 			if (items != 4) {
712 				Perl_warn( aTHX_ "error number of parameters");
713 				errno = EINVAL;
714 				RETVAL = SLURM_ERROR;
715 				break;
716 			}
717 			tmp_32 = (uint32_t)SvUV(ST(2));
718 			RETVAL = slurm_step_ctx_get(ctx, ctx_key, tmp_32, &tmp_str);
719 			if (RETVAL == SLURM_SUCCESS) {
720 				sv_setpv(ST(3), tmp_str);
721 			}
722 			break;
723 		case SLURM_STEP_CTX_USER_MANAGED_SOCKETS: /* int*, int** */
724 			if (items != 4) {
725 				Perl_warn( aTHX_ "error number of parameters");
726 				errno = EINVAL;
727 				RETVAL = SLURM_ERROR;
728 				break;
729 			}
730 			RETVAL = slurm_step_ctx_get(ctx, ctx_key, &tmp_int, &tmp_int_ptr);
731 			if (RETVAL == SLURM_SUCCESS) {
732 				AV *av = newAV();
733 				for (i = 0; i < tmp_int; i ++) {
734 					av_store_int(av, i, tmp_int_ptr[i]);
735 				}
736 				sv_setiv(ST(2), tmp_int);
737 				sv_setsv(ST(3), newRV_noinc((SV*)av));
738 			} else { /* returned val: 0, NULL */
739 				sv_setiv(ST(2), tmp_int);
740 				sv_setsv(ST(3), &PL_sv_undef);
741 			}
742 			break;
743 		default:
744 			RETVAL = slurm_step_ctx_get(ctx, ctx_key);
745 		}
746 	OUTPUT:
747 		RETVAL
748 
749 # TODO: data_type not exported in slurm.h
750 #int
751 #slurm_job_info_ctx_get(switch_jobinfo_t *jobinfo, int data_type, void *data)
752 
753 void
754 slurm_step_ctx_DESTROY(slurm_step_ctx_t *ctx)
755 	CODE:
756 		slurm_step_ctx_destroy(ctx);
757 
758 int
759 slurm_step_ctx_daemon_per_node_hack(slurm_step_ctx_t *ctx, char *node_list, uint32_t node_cnt, void *curr_task_num)
760         PREINIT:
761 	        uint32_t *tmp32;
762         CODE:
763 	        tmp32 = (uint32_t *)curr_task_num;
764 
765                 RETVAL = slurm_step_ctx_daemon_per_node_hack(ctx, node_list, node_cnt, tmp32);
766         OUTPUT:
767 	        RETVAL
768 
769 #####################################################################
770 MODULE=Slurm PACKAGE=Slurm::Stepctx PREFIX=slurm_step_
771 
772 int
773 slurm_step_launch(slurm_step_ctx_t *ctx, HV *params, HV *callbacks=NULL)
774 	PREINIT:
775 		slurm_step_launch_params_t lp;
776 		slurm_step_launch_callbacks_t *cb = NULL;
777 	CODE:
778 		if (hv_to_slurm_step_launch_params(params, &lp) < 0) {
779 			Perl_warn( aTHX_ "failed to convert slurm_step_launch_params_t");
780 			RETVAL = SLURM_ERROR;
781 		} else {
782 			if (callbacks) {
783 				set_slcb(callbacks);
784 				cb = &slcb;
785 			}
786 			RETVAL = slurm_step_launch(ctx, &lp, cb);
787 			free_slurm_step_launch_params_memory(&lp);
788 		}
789 	OUTPUT:
790 		RETVAL
791 
792 
793 int
794 slurm_step_launch_wait_start(slurm_step_ctx_t *ctx)
795 
796 void
797 slurm_step_launch_wait_finish(slurm_step_ctx_t *ctx)
798 
799 void
800 slurm_step_launch_abort(slurm_step_ctx_t *ctx)
801 
802 void
803 slurm_step_launch_fwd_signal(slurm_step_ctx_t *ctx, uint16_t signo)
804 
805 # TODO: this function is not implemented in libslurm
806 #void
807 #slurm_step_launch_fwd_wake(slurm_step_ctx_t *ctx)
808 
809 
810 ######################################################################
811 #	SLURM CONTROL CONFIGURATION READ/PRINT/UPDATE FUNCTIONS
812 ######################################################################
813 MODULE = Slurm		PACKAGE = Slurm		PREFIX=slurm_
814 #
815 # ($major, $minor, $micro) = $slurm->api_version();
816 #
817 void
818 slurm_api_version(slurm_t self, OUTLIST int major, OUTLIST int minor, OUTLIST int micro)
819 	PREINIT:
820 		long version;
821 	CODE:
822 		if (self); /* this is needed to avoid a warning about
823 			      unused variables.  But if we take slurm_t self
824 			      out of the mix Slurm-> doesn't work,
825 			      only Slurm::
826 			    */
827 		version = slurm_api_version();
828 		major = SLURM_VERSION_MAJOR(version);
829 		minor = SLURM_VERSION_MINOR(version);
830 		micro = SLURM_VERSION_MICRO(version);
831 
832 HV *
833 slurm_load_ctl_conf(slurm_t self, time_t update_time=0)
834 	PREINIT:
835 		slurm_ctl_conf_t *ctl_conf;
836 		int rc;
837 	CODE:
838 		if (self); /* this is needed to avoid a warning about
839 			      unused variables.  But if we take slurm_t self
840 			      out of the mix Slurm-> doesn't work,
841 			      only Slurm::
842 			    */
843 		rc = slurm_load_ctl_conf(update_time, &ctl_conf);
844 		if(rc == SLURM_SUCCESS) {
845 			RETVAL = newHV();
846 			sv_2mortal((SV*)RETVAL);
847 			rc = slurm_ctl_conf_to_hv(ctl_conf, RETVAL);
848 			slurm_free_ctl_conf(ctl_conf);
849 			if (rc < 0) {
850 				XSRETURN_UNDEF;
851 			}
852 		} else {
853 			XSRETURN_UNDEF;
854 		}
855 	OUTPUT:
856 		RETVAL
857 
858 void
859 slurm_print_ctl_conf(slurm_t self, FILE *out, HV *conf)
860 	PREINIT:
861 		slurm_ctl_conf_t cc;
862 	INIT:
863 		if (out == NULL) {
864 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
865 		}
866 		if (hv_to_slurm_ctl_conf(conf, &cc) < 0) {
867 			XSRETURN_UNDEF;
868 		}
869 		if (self); /* this is needed to avoid a warning about
870 			      unused variables.  But if we take slurm_t self
871 			      out of the mix Slurm-> doesn't work,
872 			      only Slurm::
873 			    */
874 	C_ARGS:
875 		out, &cc
876 
877 #
878 # $key_pairs = $slurm->ctl_conf_2_key_pairs($conf);
879 # XXX: config_key_pair_t not exported
880 #
881 List
882 slurm_ctl_conf_2_key_pairs(slurm_t self, HV *conf)
883 	PREINIT:
884 		slurm_ctl_conf_t cc;
885 	CODE:
886 		if (self); /* this is needed to avoid a warning about
887 			      unused variables.  But if we take slurm_t self
888 			      out of the mix Slurm-> doesn't work,
889 			      only Slurm::
890 			    */
891 		if (hv_to_slurm_ctl_conf(conf, &cc) < 0) {
892 			XSRETURN_UNDEF;
893 		}
894 		RETVAL = (List)slurm_ctl_conf_2_key_pairs(&cc);
895 		if(RETVAL == NULL) {
896 			XSRETURN_UNDEF;
897 		}
898 	OUTPUT:
899 		RETVAL
900 
901 
902 #
903 # $status = $slurm->load_slurmd_status();
904 #
905 HV *
906 slurm_load_slurmd_status(slurm_t self)
907 	PREINIT:
908 		slurmd_status_t *status;
909 		int rc;
910 	CODE:
911 		if (self); /* this is needed to avoid a warning about
912 			      unused variables.  But if we take slurm_t self
913 			      out of the mix Slurm-> doesn't work,
914 			      only Slurm::
915 			    */
916 		rc = slurm_load_slurmd_status(&status);
917 		if (rc == SLURM_SUCCESS) {
918 			RETVAL = newHV();
919 			sv_2mortal((SV*)RETVAL);
920 			rc = slurmd_status_to_hv(status, RETVAL);
921 			slurm_free_slurmd_status(status);
922 			if (rc < 0) {
923 				XSRETURN_UNDEF;
924 			}
925 		} else {
926 			XSRETURN_UNDEF;
927 		}
928 	OUTPUT:
929 		RETVAL
930 
931 void
932 slurm_print_slurmd_status(slurm_t self, FILE *out, HV *slurmd_status)
933 	PREINIT:
934 		slurmd_status_t st;
935 	INIT:
936 		if (out == NULL) {
937 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
938 		}
939 		if (hv_to_slurmd_status(slurmd_status, &st) < 0) {
940 			XSRETURN_UNDEF;
941 		}
942 		if (self); /* this is needed to avoid a warning about
943 			      unused variables.  But if we take slurm_t self
944 			      out of the mix Slurm-> doesn't work,
945 			      only Slurm::
946 			    */
947 	C_ARGS:
948 		out, &st
949 
950 void
951 slurm_print_key_pairs(slurm_t self, FILE *out, List key_pairs, char *title)
952 	INIT:
953 		if (out == NULL) {
954 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
955 		}
956 		if (self); /* this is needed to avoid a warning about
957 			      unused variables.  But if we take slurm_t self
958 			      out of the mix Slurm-> doesn't work,
959 			      only Slurm::
960 			    */
961 	C_ARGS:
962 		out, key_pairs, title
963 
964 int
965 slurm_update_step(slurm_t self, HV *step_msg)
966 	PREINIT:
967 		step_update_request_msg_t su_msg;
968 	CODE:
969 		if (self); /* this is needed to avoid a warning about
970 			      unused variables.  But if we take slurm_t self
971 			      out of the mix Slurm-> doesn't work,
972 			      only Slurm::
973 			    */
974 		if (hv_to_step_update_request_msg(step_msg, &su_msg) < 0) {
975 			RETVAL = SLURM_ERROR;
976 		} else {
977 			RETVAL = slurm_update_step(&su_msg);
978 		}
979 	OUTPUT:
980 		RETVAL
981 
982 
983 ######################################################################
984 #	SLURM JOB RESOURCES READ/PRINT FUNCTIONS
985 ######################################################################
986 int
987 slurm_job_cpus_allocated_on_node_id(slurm_t self, SV *job_res, int node_id)
988 	CODE:
989 		if (self); /* this is needed to avoid a warning about
990 			      unused variables.  But if we take slurm_t self
991 			      out of the mix Slurm-> doesn't work,
992 			      only Slurm::
993 			    */
994 		if(job_res) {
995 			RETVAL = slurm_job_cpus_allocated_on_node_id(
996 				(job_resources_t *)SV2ptr(job_res), node_id);
997 		} else {
998 			RETVAL = 0;
999 		}
1000 	OUTPUT:
1001 		RETVAL
1002 
1003 int
1004 slurm_job_cpus_allocated_on_node(slurm_t self, SV *job_res, char *node_name)
1005 	CODE:
1006 		if (self); /* this is needed to avoid a warning about
1007 			      unused variables.  But if we take slurm_t self
1008 			      out of the mix Slurm-> doesn't work,
1009 			      only Slurm::
1010 			    */
1011 		if(job_res) {
1012 			RETVAL = slurm_job_cpus_allocated_on_node(
1013 				(job_resources_t *)SV2ptr(job_res), node_name);
1014 		} else {
1015 			RETVAL = 0;
1016 		}
1017 	OUTPUT:
1018 		RETVAL
1019 
1020 
1021 ######################################################################
1022 #	SLURM JOB CONFIGURATION READ/PRINT/UPDATE FUNCTIONS
1023 ######################################################################
1024 MODULE = Slurm		PACKAGE = Slurm::job_info_msg_t		PREFIX=job_info_msg_t_
1025 
1026 void
1027 job_info_msg_t_DESTROY(job_info_msg_t *ji_msg)
1028 	CODE:
1029 		slurm_free_job_info_msg(ji_msg);
1030 
1031 
1032 ######################################################################
1033 MODULE = Slurm		PACKAGE = Slurm		PREFIX=slurm_
1034 
1035 # $time = $slurm->get_end_time($job_id);
1036 time_t
1037 slurm_get_end_time(slurm_t self, uint32_t job_id)
1038 	PREINIT:
1039 		time_t tmp_time;
1040 		int rc;
1041 	CODE:
1042 		if (self); /* this is needed to avoid a warning about
1043 			      unused variables.  But if we take slurm_t self
1044 			      out of the mix Slurm-> doesn't work,
1045 			      only Slurm::
1046 			    */
1047 		rc = slurm_get_end_time(job_id, &tmp_time);
1048 		if (rc == SLURM_SUCCESS) {
1049 			RETVAL = tmp_time;
1050 		} else {
1051 			XSRETURN_UNDEF;
1052 		}
1053 	OUTPUT:
1054 		RETVAL
1055 
1056 long
1057 slurm_get_rem_time(slurm_t self, uint32_t job_id)
1058 	INIT:
1059 		if (self); /* this is needed to avoid a warning about
1060 			      unused variables.  But if we take slurm_t self
1061 			      out of the mix Slurm-> doesn't work,
1062 			      only Slurm::
1063 			    */
1064 	C_ARGS:
1065 		job_id
1066 
1067 int
1068 slurm_job_node_ready(slurm_t self, uint32_t job_id)
1069 	INIT:
1070 		if (self); /* this is needed to avoid a warning about
1071 			      unused variables.  But if we take slurm_t self
1072 			      out of the mix Slurm-> doesn't work,
1073 			      only Slurm::
1074 			    */
1075 	C_ARGS:
1076 		job_id
1077 
1078 #
1079 # $resp = $slurm->load_job($job_id, $show_flags);
1080 #
1081 HV *
1082 slurm_load_job(slurm_t self, uint32_t job_id, uint16_t show_flags=0)
1083 	PREINIT:
1084 		job_info_msg_t *ji_msg;
1085 		int rc;
1086 	CODE:
1087 		if (self); /* this is needed to avoid a warning about
1088 			      unused variables.  But if we take slurm_t self
1089 			      out of the mix Slurm-> doesn't work,
1090 			      only Slurm::
1091 			    */
1092 		rc = slurm_load_job(&ji_msg, job_id, show_flags);
1093 		if (rc == SLURM_SUCCESS) {
1094 			RETVAL = newHV();
1095 			sv_2mortal((SV*)RETVAL);
1096 			rc = job_info_msg_to_hv(ji_msg, RETVAL);
1097 			/* cannot free ji_msg because RETVAL holds data in it */
1098 			if (rc >= 0) {
1099 				hv_store_ptr(RETVAL, "job_info_msg", ji_msg, "Slurm::job_info_msg_t");
1100 			}
1101 			if (rc < 0) {
1102 				XSRETURN_UNDEF;
1103 			}
1104 		} else {
1105 			XSRETURN_UNDEF;
1106 		}
1107 	OUTPUT:
1108 		RETVAL
1109 
1110 #
1111 # $resp = $slurm->load_jobs($update_time, $show_flags);
1112 #
1113 HV *
1114 slurm_load_jobs(slurm_t self, time_t update_time=0, uint16_t show_flags=0)
1115 	PREINIT:
1116 		job_info_msg_t *ji_msg;
1117 		int rc;
1118 	CODE:
1119 		if (self); /* this is needed to avoid a warning about
1120 			      unused variables.  But if we take slurm_t self
1121 			      out of the mix Slurm-> doesn't work,
1122 			      only Slurm::
1123 			    */
1124 		rc = slurm_load_jobs(update_time, &ji_msg, show_flags);
1125 		if (rc == SLURM_SUCCESS) {
1126 			RETVAL = newHV();
1127 			sv_2mortal((SV*)RETVAL);
1128 			rc = job_info_msg_to_hv(ji_msg, RETVAL);
1129 			/* cannot free ji_msg because RETVAL holds data in it */
1130 			if (rc >= 0) {
1131 				hv_store_ptr(RETVAL, "job_info_msg", ji_msg, "Slurm::job_info_msg_t");
1132 			}
1133 			if (rc < 0) {
1134 				XSRETURN_UNDEF;
1135 			}
1136 		} else {
1137 			XSRETURN_UNDEF;
1138 		}
1139 	OUTPUT:
1140 		RETVAL
1141 
1142 int
1143 slurm_notify_job(slurm_t self, uint32_t job_id, char *message)
1144 	INIT:
1145 		if (self); /* this is needed to avoid a warning about
1146 			      unused variables.  But if we take slurm_t self
1147 			      out of the mix Slurm-> doesn't work,
1148 			      only Slurm::
1149 			    */
1150 	C_ARGS:
1151 		job_id, message
1152 
1153 #
1154 # $job_id = $slurm->pid2jobid($job_pid);
1155 #
1156 uint32_t
1157 slurm_pid2jobid(slurm_t self, pid_t job_pid)
1158 	PREINIT:
1159 		uint32_t tmp_pid;
1160 		int rc;
1161 	CODE:
1162 		if (self); /* this is needed to avoid a warning about
1163 			      unused variables.  But if we take slurm_t self
1164 			      out of the mix Slurm-> doesn't work,
1165 			      only Slurm::
1166 			    */
1167 		rc = slurm_pid2jobid(job_pid, &tmp_pid);
1168 		if (rc == SLURM_SUCCESS) {
1169 			RETVAL = tmp_pid;
1170 		} else {
1171 			XSRETURN_UNDEF;
1172 		}
1173 	OUTPUT:
1174 		RETVAL
1175 
1176 void
1177 slurm_print_job_info(slurm_t self, FILE* out, HV *job_info, int one_liner=0)
1178 	PREINIT:
1179 		job_info_t ji;
1180 	INIT:
1181 		if (self); /* this is needed to avoid a warning about
1182 			      unused variables.  But if we take slurm_t self
1183 			      out of the mix Slurm-> doesn't work,
1184 			      only Slurm::
1185 			    */
1186 		if (out == NULL) {
1187 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1188 		}
1189 		if (hv_to_job_info(job_info, &ji) < 0) {
1190 			XSRETURN_UNDEF;
1191 		}
1192 	C_ARGS:
1193 		out, &ji, one_liner
1194 	CLEANUP:
1195 		xfree(ji.exc_node_inx);
1196 		xfree(ji.node_inx);
1197 		xfree(ji.req_node_inx);
1198 
1199 void
1200 slurm_print_job_info_msg(slurm_t self, FILE *out, HV *job_info_msg, int one_liner=0)
1201 	PREINIT:
1202 		job_info_msg_t ji_msg;
1203 	INIT:
1204 		if (self); /* this is needed to avoid a warning about
1205 			      unused variables.  But if we take slurm_t self
1206 			      out of the mix Slurm-> doesn't work,
1207 			      only Slurm::
1208 			    */
1209 		if (out == NULL) {
1210 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1211 		}
1212 		if (hv_to_job_info_msg(job_info_msg, &ji_msg) < 0) {
1213 			XSRETURN_UNDEF;
1214 		}
1215 	C_ARGS:
1216 		out, &ji_msg, one_liner
1217 	CLEANUP:
1218 		xfree(ji_msg.job_array);
1219 
1220 char_xfree *
1221 slurm_sprint_job_info(slurm_t self, HV *job_info, int one_liner=0)
1222 	PREINIT:
1223 		job_info_t ji;
1224 		char *tmp_str = NULL;
1225 	CODE:
1226 		if (self); /* this is needed to avoid a warning about
1227 			      unused variables.  But if we take slurm_t self
1228 			      out of the mix Slurm-> doesn't work,
1229 			      only Slurm::
1230 			    */
1231 		if(hv_to_job_info(job_info, &ji) < 0) {
1232 			XSRETURN_UNDEF;
1233 		}
1234 		tmp_str = slurm_sprint_job_info(&ji, one_liner);
1235 		xfree(ji.exc_node_inx);
1236 		xfree(ji.node_inx);
1237 		xfree(ji.req_node_inx);
1238 		RETVAL = tmp_str;
1239 	OUTPUT:
1240 		RETVAL
1241 
1242 int
1243 slurm_update_job(slurm_t self, HV *job_info)
1244 	PREINIT:
1245 		job_desc_msg_t update_msg;
1246 	INIT:
1247 		if (self); /* this is needed to avoid a warning about
1248 			      unused variables.  But if we take slurm_t self
1249 			      out of the mix Slurm-> doesn't work,
1250 			      only Slurm::
1251 			    */
1252 		if(hv_to_job_desc_msg(job_info, &update_msg) < 0) {
1253 			XSRETURN_UNDEF;
1254 		}
1255 	C_ARGS:
1256 		&update_msg
1257 	CLEANUP:
1258 		free_job_desc_msg_memory(&update_msg);
1259 
1260 
1261 
1262 ######################################################################
1263 #	SLURM JOB STEP CONFIGURATION READ/PRINT/UPDATE FUNCTIONS
1264 ######################################################################
1265 
1266 HV *
1267 slurm_get_job_steps(slurm_t self, time_t update_time=0, uint32_t job_id=NO_VAL, uint32_t step_id=NO_VAL, uint16_t show_flags=0)
1268 	PREINIT:
1269 		int rc;
1270 		job_step_info_response_msg_t *resp_msg;
1271 	CODE:
1272 		if (self); /* this is needed to avoid a warning about
1273 			      unused variables.  But if we take slurm_t self
1274 			      out of the mix Slurm-> doesn't work,
1275 			      only Slurm::
1276 			    */
1277 		rc = slurm_get_job_steps(update_time, job_id, step_id, &resp_msg, show_flags);
1278 		if(rc == SLURM_SUCCESS) {
1279 			RETVAL = newHV();
1280 			sv_2mortal((SV*)RETVAL);
1281 			rc = job_step_info_response_msg_to_hv(resp_msg, RETVAL);
1282 			slurm_free_job_step_info_response_msg(resp_msg);
1283 			if (rc < 0) {
1284 				XSRETURN_UNDEF;
1285 			}
1286 		} else {
1287 			XSRETURN_UNDEF;
1288 		}
1289 	OUTPUT:
1290 		RETVAL
1291 
1292 void
1293 slurm_print_job_step_info_msg(slurm_t self, FILE *out, HV *step_info_msg, int one_liner=0)
1294 	PREINIT:
1295 		job_step_info_response_msg_t si_msg;
1296 	INIT:
1297 		if (self); /* this is needed to avoid a warning about
1298 			      unused variables.  But if we take slurm_t self
1299 			      out of the mix Slurm-> doesn't work,
1300 			      only Slurm::
1301 			    */
1302 		if (out == NULL) {
1303 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1304 		}
1305 		if(hv_to_job_step_info_response_msg(step_info_msg, &si_msg) < 0) {
1306 			XSRETURN_UNDEF;
1307 		}
1308 	C_ARGS:
1309 		out, &si_msg, one_liner
1310 	CLEANUP:
1311 		xfree(si_msg.job_steps);
1312 
1313 void
1314 slurm_print_job_step_info(slurm_t self, FILE *out, HV *step_info, int one_liner=0)
1315 	PREINIT:
1316 		job_step_info_t si;
1317 	INIT:
1318 		if (self); /* this is needed to avoid a warning about
1319 			      unused variables.  But if we take slurm_t self
1320 			      out of the mix Slurm-> doesn't work,
1321 			      only Slurm::
1322 			    */
1323 		if (out == NULL) {
1324 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1325 		}
1326 		if(hv_to_job_step_info(step_info, &si) < 0) {
1327 			XSRETURN_UNDEF;
1328 		}
1329 	C_ARGS:
1330 		out, &si, one_liner
1331 	CLEANUP:
1332 		xfree(si.node_inx);
1333 
1334 char_xfree *
1335 slurm_sprint_job_step_info(slurm_t self, HV *step_info, int one_liner=0)
1336 	PREINIT:
1337 		job_step_info_t si;
1338 	CODE:
1339 		if (self); /* this is needed to avoid a warning about
1340 			      unused variables.  But if we take slurm_t self
1341 			      out of the mix Slurm-> doesn't work,
1342 			      only Slurm::
1343 			    */
1344 		if(hv_to_job_step_info(step_info, &si) < 0) {
1345 			XSRETURN_UNDEF;
1346 		}
1347 		RETVAL = slurm_sprint_job_step_info(&si, one_liner);
1348 		xfree(si.node_inx);
1349 	OUTPUT:
1350 		RETVAL
1351 
1352 HV *
1353 slurm_job_step_layout_get(slurm_t self, uint32_t job_id, uint32_t step_id)
1354 	PREINIT:
1355 		int rc;
1356 		slurm_step_layout_t *layout;
1357 	CODE:
1358 		if (self); /* this is needed to avoid a warning about
1359 			      unused variables.  But if we take slurm_t self
1360 			      out of the mix Slurm-> doesn't work,
1361 			      only Slurm::
1362 			    */
1363 		layout = slurm_job_step_layout_get(job_id, step_id);
1364 		if(layout == NULL) {
1365 			XSRETURN_UNDEF;
1366 		} else {
1367 			RETVAL = newHV();
1368 			sv_2mortal((SV*)RETVAL);
1369 			rc = slurm_step_layout_to_hv(layout, RETVAL);
1370 			slurm_job_step_layout_free(layout);
1371 			if (rc < 0) {
1372 				XSRETURN_UNDEF;
1373 			}
1374 		}
1375 	OUTPUT:
1376 		RETVAL
1377 
1378 HV *
1379 slurm_job_step_stat(slurm_t self, uint32_t job_id, uint32_t step_id, char *nodelist=NULL, uint16_t protocol_version)
1380 	PREINIT:
1381 		int rc;
1382 		job_step_stat_response_msg_t *resp_msg;
1383 	CODE:
1384 		if (self); /* this is needed to avoid a warning about
1385 			      unused variables.  But if we take slurm_t self
1386 			      out of the mix Slurm-> doesn't work,
1387 			      only Slurm::
1388 			    */
1389                 rc = slurm_job_step_stat(job_id, step_id, nodelist,
1390 					 protocol_version, &resp_msg);
1391 		if (rc == SLURM_SUCCESS) {
1392 			RETVAL = newHV();
1393 			sv_2mortal((SV*)RETVAL);
1394 			rc = job_step_stat_response_msg_to_hv(resp_msg, RETVAL);
1395 			slurm_job_step_stat_response_msg_free(resp_msg);
1396 			if (rc < 0) {
1397 				XSRETURN_UNDEF;
1398 			}
1399 		} else {
1400 			errno = rc;
1401 			XSRETURN_UNDEF;
1402 		}
1403 	OUTPUT:
1404 		RETVAL
1405 
1406 HV *
1407 slurm_job_step_get_pids(slurm_t self, uint32_t job_id, uint32_t step_id, char *nodelist=NULL)
1408 	PREINIT:
1409 		int rc;
1410 		job_step_pids_response_msg_t *resp_msg = NULL;
1411 	CODE:
1412 		if (self); /* this is needed to avoid a warning about
1413 			      unused variables.  But if we take slurm_t self
1414 			      out of the mix Slurm-> doesn't work,
1415 			      only Slurm::
1416 			    */
1417 		rc = slurm_job_step_get_pids(job_id, step_id, nodelist, &resp_msg);
1418 		if (rc == SLURM_SUCCESS) {
1419 			RETVAL = newHV();
1420 			sv_2mortal((SV*)RETVAL);
1421 			rc = job_step_pids_response_msg_to_hv(resp_msg, RETVAL);
1422 			slurm_job_step_pids_response_msg_free(resp_msg);
1423 			if (rc < 0) {
1424 				XSRETURN_UNDEF;
1425 			}
1426 		} else {
1427 			errno = rc;
1428 			XSRETURN_UNDEF;
1429 		}
1430 	OUTPUT:
1431 		RETVAL
1432 
1433 ######################################################################
1434 #	SLURM NODE CONFIGURATION READ/PRINT/UPDATE FUNCTIONS
1435 ######################################################################
1436 MODULE = Slurm		PACKAGE = Slurm::node_info_msg_t	PREFIX=node_info_msg_t_
1437 
1438 void
1439 node_info_msg_t_DESTROY(node_info_msg_t *ni_msg)
1440 	CODE:
1441 		slurm_free_node_info_msg(ni_msg);
1442 
1443 
1444 ######################################################################
1445 MODULE = Slurm		PACKAGE = Slurm		PREFIX=slurm_
1446 
1447 HV *
1448 slurm_load_node(slurm_t self, time_t update_time=0, uint16_t show_flags=0)
1449 	PREINIT:
1450 		node_info_msg_t *ni_msg = NULL;
1451 		int rc;
1452 	CODE:
1453 		if (self); /* this is needed to avoid a warning about
1454 			      unused variables.  But if we take slurm_t self
1455 			      out of the mix Slurm-> doesn't work,
1456 			      only Slurm::
1457 			    */
1458 		rc = slurm_load_node(update_time, &ni_msg,
1459 				     show_flags | SHOW_MIXED);
1460 		if (rc == SLURM_SUCCESS) {
1461 			RETVAL = newHV();
1462 			sv_2mortal((SV*)RETVAL);
1463 			/* RETVAL holds ni_msg->select_nodeinfo, so delay free-ing the msg */
1464 			rc = node_info_msg_to_hv(ni_msg, RETVAL);
1465 			if (rc >= 0) {
1466 				rc = hv_store_ptr(RETVAL, "node_info_msg", ni_msg, "Slurm::node_info_msg_t");
1467 			}
1468 			if (rc < 0) {
1469 				XSRETURN_UNDEF;
1470 			}
1471 		} else {
1472 			XSRETURN_UNDEF;
1473 		}
1474 	OUTPUT:
1475 		RETVAL
1476 
1477 HV *
1478 slurm_load_single_node(slurm_t self, char *node_name, uint16_t show_flags=0)
1479 	PREINIT:
1480 		node_info_msg_t *ni_msg = NULL;
1481 		int rc;
1482 	CODE:
1483 		if (self); /* this is needed to avoid a warning about
1484 			      unused variables.  But if we take slurm_t self
1485 			      out of the mix Slurm-> doesn't work,
1486 			      only Slurm::
1487 			    */
1488 		rc = slurm_load_node_single(&ni_msg, node_name, show_flags | SHOW_MIXED);
1489 
1490 		if (rc == SLURM_SUCCESS) {
1491 			RETVAL = newHV();
1492 			sv_2mortal((SV*)RETVAL);
1493 			/* RETVAL holds ni_msg->select_nodeinfo, so delay free-ing the msg */
1494 			rc = node_info_msg_to_hv(ni_msg, RETVAL);
1495 			if (rc >= 0) {
1496 				rc = hv_store_ptr(RETVAL, "node_info_msg", ni_msg, "Slurm::node_info_msg_t");
1497 			}
1498 			if (rc < 0) {
1499 				XSRETURN_UNDEF;
1500 			}
1501 		} else {
1502 			XSRETURN_UNDEF;
1503 		}
1504 	OUTPUT:
1505 		RETVAL
1506 
1507 void
1508 slurm_print_node_info_msg(slurm_t self, FILE *out, HV *node_info_msg, int one_liner=0)
1509 	PREINIT:
1510 		node_info_msg_t ni_msg;
1511 	INIT:
1512 		if (self); /* this is needed to avoid a warning about
1513 			      unused variables.  But if we take slurm_t self
1514 			      out of the mix Slurm-> doesn't work,
1515 			      only Slurm::
1516 			    */
1517 		if (out == NULL) {
1518 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1519 		}
1520 		if(hv_to_node_info_msg(node_info_msg, &ni_msg) < 0) {
1521 			XSRETURN_UNDEF;
1522 		}
1523 	C_ARGS:
1524 		out, &ni_msg, one_liner
1525 	CLEANUP:
1526 		xfree(ni_msg.node_array);
1527 
1528 void
1529 slurm_print_node_table(slurm_t self, FILE *out, HV *node_info, int one_liner=0)
1530 	PREINIT:
1531 		node_info_t ni;
1532 	INIT:
1533 		if (self); /* this is needed to avoid a warning about
1534 			      unused variables.  But if we take slurm_t self
1535 			      out of the mix Slurm-> doesn't work,
1536 			      only Slurm::
1537 			    */
1538 		if (out == NULL) {
1539 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1540 		}
1541 		if(hv_to_node_info(node_info, &ni) < 0) {
1542 			XSRETURN_UNDEF;
1543 		}
1544 	C_ARGS:
1545 		out, &ni, one_liner
1546 
1547 char_xfree *
1548 slurm_sprint_node_table(slurm_t self, HV *node_info, int one_liner=0)
1549 	PREINIT:
1550 		node_info_t ni;
1551 	CODE:
1552 		if (self); /* this is needed to avoid a warning about
1553 			      unused variables.  But if we take slurm_t self
1554 			      out of the mix Slurm-> doesn't work,
1555 			      only Slurm::
1556 			    */
1557 		if(hv_to_node_info(node_info, &ni) < 0) {
1558 			XSRETURN_UNDEF;
1559 		}
1560 		RETVAL = slurm_sprint_node_table(&ni, one_liner);
1561 	OUTPUT:
1562 		RETVAL
1563 
1564 int
1565 slurm_update_node(slurm_t self, HV *update_req)
1566 	PREINIT:
1567 		update_node_msg_t node_msg;
1568 	INIT:
1569 		if (self); /* this is needed to avoid a warning about
1570 			      unused variables.  But if we take slurm_t self
1571 			      out of the mix Slurm-> doesn't work,
1572 			      only Slurm::
1573 			    */
1574 		if(hv_to_update_node_msg(update_req, &node_msg) < 0) {
1575 			XSRETURN_UNDEF;
1576 		}
1577 	C_ARGS:
1578 		&node_msg
1579 
1580 
1581 ######################################################################
1582 #	SLURM SWITCH TOPOLOGY CONFIGURATION READ/PRINT FUNCTIONS
1583 ######################################################################
1584 
1585 HV *
1586 slurm_load_topo(slurm_t self)
1587 	PREINIT:
1588 		topo_info_response_msg_t *topo_info_msg = NULL;
1589 		int rc;
1590 	CODE:
1591 		if (self); /* this is needed to avoid a warning about
1592 			      unused variables.  But if we take slurm_t self
1593 			      out of the mix Slurm-> doesn't work,
1594 			      only Slurm::
1595 			    */
1596 		rc = slurm_load_topo( &topo_info_msg);
1597 		if(rc == SLURM_SUCCESS) {
1598 			RETVAL = newHV();
1599 			sv_2mortal((SV*)RETVAL);
1600 			rc = topo_info_response_msg_to_hv(topo_info_msg, RETVAL);
1601 			slurm_free_topo_info_msg(topo_info_msg);
1602 			if (rc < 0) {
1603 				XSRETURN_UNDEF;
1604 			}
1605 		} else {
1606 			XSRETURN_UNDEF;
1607 		}
1608 	OUTPUT:
1609 		RETVAL
1610 
1611 void
1612 slurm_print_topo_info_msg(slurm_t self, FILE *out, HV *topo_info_msg, int one_liner=0)
1613 	PREINIT:
1614 		topo_info_response_msg_t ti_msg;
1615 	INIT:
1616 		if (self); /* this is needed to avoid a warning about
1617 			      unused variables.  But if we take slurm_t self
1618 			      out of the mix Slurm-> doesn't work,
1619 			      only Slurm::
1620 			    */
1621 		if (out == NULL) {
1622 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1623 		}
1624 		if(hv_to_topo_info_response_msg(topo_info_msg, &ti_msg) < 0) {
1625 			XSRETURN_UNDEF;
1626 		}
1627 	C_ARGS:
1628 		out, &ti_msg, one_liner
1629 	CLEANUP:
1630 		xfree(ti_msg.topo_array);
1631 
1632 void
1633 slurm_print_topo_record(slurm_t self, FILE *out, HV *topo_info, int one_liner=0)
1634 	PREINIT:
1635 		topo_info_t ti;
1636 	INIT:
1637 		if (self); /* this is needed to avoid a warning about
1638 			      unused variables.  But if we take slurm_t self
1639 			      out of the mix Slurm-> doesn't work,
1640 			      only Slurm::
1641 			    */
1642 		if (out == NULL) {
1643 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1644 		}
1645 		if(hv_to_topo_info(topo_info, &ti) < 0) {
1646 			XSRETURN_UNDEF;
1647 		}
1648 	C_ARGS:
1649 		out, &ti, one_liner
1650 
1651 
1652 ######################################################################
1653 #	SLURM SELECT READ/PRINT/UPDATE FUNCTIONS
1654 ######################################################################
1655 #
1656 # $rc = $slurm->get_select_nodeinfo($nodeinfo, $data_type, $state, $data);
1657 #
1658 int
1659 slurm_get_select_nodeinfo(slurm_t self, dynamic_plugin_data_t *nodeinfo, uint32_t data_type, uint32_t state, SV *data)
1660 	PREINIT:
1661 		uint16_t tmp_16;
1662 		select_nodeinfo_t *tmp_ptr;
1663 	CODE:
1664 		if (self); /* this is needed to avoid a warning about
1665 			      unused variables.  But if we take slurm_t self
1666 			      out of the mix Slurm-> doesn't work,
1667 			      only Slurm::
1668 			    */
1669 		switch(data_type) {
1670 		case SELECT_NODEDATA_SUBCNT:      /* data-> uint16_t */
1671 			RETVAL = slurm_get_select_nodeinfo(nodeinfo, data_type, state, &tmp_16);
1672 			if (RETVAL == 0) {
1673 				sv_setuv(data, (UV)tmp_16);
1674 			}
1675 			break;
1676 		case SELECT_NODEDATA_PTR:         /* data-> select_nodeinfo_t *nodeinfo */
1677 			RETVAL = slurm_get_select_nodeinfo(nodeinfo, data_type, state, &tmp_ptr);
1678 			if (RETVAL == 0) {
1679 				sv_setref_pv(data, "Slurm::select_nodeinfo_t", (void*)tmp_ptr);
1680 			}
1681 			break;
1682 		default:
1683 			RETVAL = slurm_get_select_nodeinfo(nodeinfo, data_type, state, NULL);
1684 		}
1685 	OUTPUT:
1686 		RETVAL
1687 
1688 ######################################################################
1689 #	SLURM PARTITION CONFIGURATION READ/PRINT/UPDATE FUNCTIONS
1690 ######################################################################
1691 
1692 HV *
1693 slurm_load_partitions(slurm_t self, time_t update_time=0, uint16_t show_flags=0)
1694 	PREINIT:
1695 		partition_info_msg_t *part_info_msg;
1696 		int rc;
1697 	CODE:
1698 		if (self); /* this is needed to avoid a warning about
1699 			      unused variables.  But if we take slurm_t self
1700 			      out of the mix Slurm-> doesn't work,
1701 			      only Slurm::
1702 			    */
1703 		rc = slurm_load_partitions(update_time, &part_info_msg,
1704 					   show_flags);
1705 		if (rc == SLURM_SUCCESS) {
1706 			RETVAL = newHV();
1707 			sv_2mortal((SV*)RETVAL);
1708 			rc = partition_info_msg_to_hv(part_info_msg, RETVAL);
1709 			slurm_free_partition_info_msg(part_info_msg);
1710 			if (rc < 0) {
1711 				XSRETURN_UNDEF;
1712 			}
1713 		} else {
1714 			XSRETURN_UNDEF;
1715 		}
1716 	OUTPUT:
1717 		RETVAL
1718 
1719 void
1720 slurm_print_partition_info_msg(slurm_t self, FILE *out, HV *part_info_msg, int one_liner=0)
1721 	PREINIT:
1722 		partition_info_msg_t pi_msg;
1723 	INIT:
1724 		if (self); /* this is needed to avoid a warning about
1725 			      unused variables.  But if we take slurm_t self
1726 			      out of the mix Slurm-> doesn't work,
1727 			      only Slurm::
1728 			    */
1729 		if (out == NULL) {
1730 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1731 		}
1732 		if(hv_to_partition_info_msg(part_info_msg, &pi_msg) < 0) {
1733 			XSRETURN_UNDEF;
1734 		}
1735 	C_ARGS:
1736 		out, &pi_msg, one_liner
1737 	CLEANUP:
1738 		xfree(pi_msg.partition_array);
1739 
1740 void
1741 slurm_print_partition_info(slurm_t self, FILE *out, HV *part_info, int one_liner=0)
1742 	PREINIT:
1743 		partition_info_t pi;
1744 	INIT:
1745 		if (self); /* this is needed to avoid a warning about
1746 			      unused variables.  But if we take slurm_t self
1747 			      out of the mix Slurm-> doesn't work,
1748 			      only Slurm::
1749 			    */
1750 		if (out == NULL) {
1751 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1752 		}
1753 		if(hv_to_partition_info(part_info, &pi) < 0) {
1754 			XSRETURN_UNDEF;
1755 		}
1756 	C_ARGS:
1757 		out, &pi, one_liner
1758 	CLEANUP:
1759 		xfree(pi.node_inx);
1760 
1761 char_xfree *
1762 slurm_sprint_partition_info(slurm_t self, HV *part_info, int one_liner=0)
1763 	PREINIT:
1764 		partition_info_t pi;
1765 	CODE:
1766 		if (self); /* this is needed to avoid a warning about
1767 			      unused variables.  But if we take slurm_t self
1768 			      out of the mix Slurm-> doesn't work,
1769 			      only Slurm::
1770 			    */
1771 		if(hv_to_partition_info(part_info, &pi) < 0) {
1772 			XSRETURN_UNDEF;
1773 		}
1774 		RETVAL = slurm_sprint_partition_info(&pi, one_liner);
1775 		xfree(pi.node_inx);
1776 	OUTPUT:
1777 		RETVAL
1778 
1779 int
1780 slurm_create_partition(slurm_t self, HV *part_info)
1781 	PREINIT:
1782 		update_part_msg_t update_msg;
1783 	INIT:
1784 		if (self); /* this is needed to avoid a warning about
1785 			      unused variables.  But if we take slurm_t self
1786 			      out of the mix Slurm-> doesn't work,
1787 			      only Slurm::
1788 			    */
1789 		if(hv_to_update_part_msg(part_info, &update_msg) < 0) {
1790 			XSRETURN_UNDEF;
1791 		}
1792 	C_ARGS:
1793 		&update_msg
1794 
1795 int
1796 slurm_update_partition(slurm_t self, HV *part_info)
1797 	PREINIT:
1798 		update_part_msg_t update_msg;
1799 	INIT:
1800 		if (self); /* this is needed to avoid a warning about
1801 			      unused variables.  But if we take slurm_t self
1802 			      out of the mix Slurm-> doesn't work,
1803 			      only Slurm::
1804 			    */
1805 		if(hv_to_update_part_msg(part_info, &update_msg) < 0) {
1806 			XSRETURN_UNDEF;
1807 		}
1808 	C_ARGS:
1809 		&update_msg
1810 
1811 int
1812 slurm_delete_partition(slurm_t self, HV *delete_part_msg)
1813 	PREINIT:
1814 		delete_part_msg_t dp_msg;
1815 	INIT:
1816 		if (self); /* this is needed to avoid a warning about
1817 			      unused variables.  But if we take slurm_t self
1818 			      out of the mix Slurm-> doesn't work,
1819 			      only Slurm::
1820 			    */
1821 		if(hv_to_delete_part_msg(delete_part_msg, &dp_msg) < 0) {
1822 			XSRETURN_UNDEF;
1823 		}
1824 	C_ARGS:
1825 		&dp_msg
1826 
1827 
1828 ######################################################################
1829 #	SLURM RESERVATION CONFIGURATION READ/PRINT/UPDATE FUNCTIONS
1830 ######################################################################
1831 
1832 HV *
1833 slurm_load_reservations(slurm_t self, time_t update_time=0)
1834 	PREINIT:
1835 		reserve_info_msg_t *resv_info_msg = NULL;
1836 		int rc;
1837 	CODE:
1838 		if (self); /* this is needed to avoid a warning about
1839 			      unused variables.  But if we take slurm_t self
1840 			      out of the mix Slurm-> doesn't work,
1841 			      only Slurm::
1842 			    */
1843 		rc = slurm_load_reservations(update_time, &resv_info_msg);
1844 		if(rc == SLURM_SUCCESS) {
1845 			RETVAL = newHV();
1846 			sv_2mortal((SV*)RETVAL);
1847 			rc = reserve_info_msg_to_hv(resv_info_msg, RETVAL);
1848 			slurm_free_reservation_info_msg(resv_info_msg);
1849 			if (rc < 0) {
1850 				XSRETURN_UNDEF;
1851 			}
1852 		} else {
1853 			XSRETURN_UNDEF;
1854 		}
1855 	OUTPUT:
1856 		RETVAL
1857 
1858 char_free *
1859 slurm_create_reservation(slurm_t self, HV *res_info)
1860 	PREINIT:
1861 		resv_desc_msg_t resv_msg;
1862 	CODE:
1863 		if (self); /* this is needed to avoid a warning about
1864 			      unused variables.  But if we take slurm_t self
1865 			      out of the mix Slurm-> doesn't work,
1866 			      only Slurm::
1867 			    */
1868 		if(hv_to_update_reservation_msg(res_info, &resv_msg) < 0) {
1869 			XSRETURN_UNDEF;
1870 		}
1871 		RETVAL = slurm_create_reservation(&resv_msg);
1872 		if (RETVAL == NULL) {
1873 			XSRETURN_UNDEF;
1874 		}
1875 	OUTPUT:
1876 		RETVAL
1877 
1878 int
1879 slurm_update_reservation(slurm_t self, HV *res_info)
1880 	PREINIT:
1881 		resv_desc_msg_t resv_msg;
1882 	INIT:
1883 		if (self); /* this is needed to avoid a warning about
1884 			      unused variables.  But if we take slurm_t self
1885 			      out of the mix Slurm-> doesn't work,
1886 			      only Slurm::
1887 			    */
1888 		if(hv_to_update_reservation_msg(res_info, &resv_msg) < 0) {
1889 			XSRETURN_UNDEF;
1890 		}
1891 	C_ARGS:
1892 		&resv_msg
1893 
1894 int
1895 slurm_delete_reservation(slurm_t self, HV *res_info)
1896 	PREINIT:
1897 		reservation_name_msg_t resv_name;
1898 	INIT:
1899 		if (self); /* this is needed to avoid a warning about
1900 			      unused variables.  But if we take slurm_t self
1901 			      out of the mix Slurm-> doesn't work,
1902 			      only Slurm::
1903 			    */
1904 		if(hv_to_delete_reservation_msg(res_info, &resv_name) < 0) {
1905 			XSRETURN_UNDEF;
1906 		}
1907 	C_ARGS:
1908 		&resv_name
1909 
1910 void
1911 slurm_print_reservation_info_msg(slurm_t self, FILE *out, HV *resv_info_msg, int one_liner=0)
1912 	PREINIT:
1913 		reserve_info_msg_t ri_msg;
1914 		int i;
1915 	INIT:
1916 		if (self); /* this is needed to avoid a warning about
1917 			      unused variables.  But if we take slurm_t self
1918 			      out of the mix Slurm-> doesn't work,
1919 			      only Slurm::
1920 			    */
1921 		if (out == NULL) {
1922 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1923 		}
1924 		if(hv_to_reserve_info_msg(resv_info_msg, &ri_msg) < 0) {
1925 			XSRETURN_UNDEF;
1926 		}
1927 	C_ARGS:
1928 		out, &ri_msg, one_liner
1929 	CLEANUP:
1930 		for (i = 0; i < ri_msg.record_count; i ++)
1931 			xfree(ri_msg.reservation_array[i]);
1932 		xfree(ri_msg.reservation_array);
1933 
1934 void
1935 slurm_print_reservation_info(slurm_t self, FILE *out, HV *resv_info, int one_liner=0)
1936 	PREINIT:
1937 		reserve_info_t ri;
1938 	INIT:
1939 		if (self); /* this is needed to avoid a warning about
1940 			      unused variables.  But if we take slurm_t self
1941 			      out of the mix Slurm-> doesn't work,
1942 			      only Slurm::
1943 			    */
1944 		if (out == NULL) {
1945 			Perl_croak (aTHX_ "Invalid output stream specified: FILE not found");
1946 		}
1947 		if(hv_to_reserve_info(resv_info, &ri) < 0) {
1948 			XSRETURN_UNDEF;
1949 		}
1950 	C_ARGS:
1951 		out, &ri, one_liner
1952 	CLEANUP:
1953 		xfree(ri.node_inx);
1954 
1955 char_xfree *
1956 slurm_sprint_reservation_info(slurm_t self, HV *resv_info, int one_liner=0)
1957 	PREINIT:
1958 		reserve_info_t ri;
1959 	CODE:
1960 		if (self); /* this is needed to avoid a warning about
1961 			      unused variables.  But if we take slurm_t self
1962 			      out of the mix Slurm-> doesn't work,
1963 			      only Slurm::
1964 			    */
1965 		if(hv_to_reserve_info(resv_info, &ri) < 0) {
1966 			XSRETURN_UNDEF;
1967 		}
1968 		RETVAL = slurm_sprint_reservation_info(&ri, one_liner);
1969 		xfree(ri.node_inx);
1970 	OUTPUT:
1971 		RETVAL
1972 
1973 
1974 ######################################################################
1975 #	SLURM PING/RECONFIGURE/SHUTDOWN FUNCTIONS
1976 ######################################################################
1977 
1978 int
1979 slurm_ping(slurm_t self, uint16_t primary=1)
1980 	INIT:
1981 		if (self); /* this is needed to avoid a warning about
1982 			      unused variables.  But if we take slurm_t self
1983 			      out of the mix Slurm-> doesn't work,
1984 			      only Slurm::
1985 			    */
1986 	C_ARGS:
1987 		primary
1988 
1989 int
1990 slurm_reconfigure(slurm_t self)
1991 	INIT:
1992 		if (self); /* this is needed to avoid a warning about
1993 			      unused variables.  But if we take slurm_t self
1994 			      out of the mix Slurm-> doesn't work,
1995 			      only Slurm::
1996 			    */
1997 	C_ARGS:
1998 
1999 int
2000 slurm_shutdown(slurm_t self, uint16_t options=0)
2001 	INIT:
2002 		if (self); /* this is needed to avoid a warning about
2003 			      unused variables.  But if we take slurm_t self
2004 			      out of the mix Slurm-> doesn't work,
2005 			      only Slurm::
2006 			    */
2007 	C_ARGS:
2008 		options
2009 
2010 int
2011 slurm_takeover(slurm_t self, int backup_inx=1)
2012 	INIT:
2013 		if (self); /* this is needed to avoid a warning about
2014 			      unused variables.  But if we take slurm_t self
2015 			      out of the mix Slurm-> doesn't work,
2016 			      only Slurm::
2017 			    */
2018 	C_ARGS:
2019 		backup_inx
2020 
2021 int
2022 slurm_set_debug_level(slurm_t self, uint32_t debug_level)
2023 	INIT:
2024 		if (self); /* this is needed to avoid a warning about
2025 			      unused variables.  But if we take slurm_t self
2026 			      out of the mix Slurm-> doesn't work,
2027 			      only Slurm::
2028 			    */
2029 	C_ARGS:
2030 		debug_level
2031 
2032 int
2033 slurm_set_schedlog_level(slurm_t self, uint32_t schedlog_level)
2034 	INIT:
2035 		if (self); /* this is needed to avoid a warning about
2036 			      unused variables.  But if we take slurm_t self
2037 			      out of the mix Slurm-> doesn't work,
2038 			      only Slurm::
2039 			    */
2040 	C_ARGS:
2041 		schedlog_level
2042 
2043 
2044 ######################################################################
2045 #	SLURM JOB SUSPEND FUNCTIONS
2046 ######################################################################
2047 
2048 int
2049 slurm_suspend(slurm_t self, uint32_t job_id)
2050 	INIT:
2051 		if (self); /* this is needed to avoid a warning about
2052 			      unused variables.  But if we take slurm_t self
2053 			      out of the mix Slurm-> doesn't work,
2054 			      only Slurm::
2055 			    */
2056 	C_ARGS:
2057 		job_id
2058 
2059 int
2060 slurm_resume(slurm_t self, uint32_t job_id)
2061 	INIT:
2062 		if (self); /* this is needed to avoid a warning about
2063 			      unused variables.  But if we take slurm_t self
2064 			      out of the mix Slurm-> doesn't work,
2065 			      only Slurm::
2066 			    */
2067 	C_ARGS:
2068 		job_id
2069 
2070 int
2071 slurm_requeue(slurm_t self, uint32_t job_id, uint32_t state)
2072 	INIT:
2073 		if (self); /* this is needed to avoid a warning about
2074 			      unused variables.  But if we take slurm_t self
2075 			      out of the mix Slurm-> doesn't work,
2076 			      only Slurm::
2077 			    */
2078 	C_ARGS:
2079 		job_id, state
2080 
2081 
2082 ######################################################################
2083 #	SLURM TRIGGER FUNCTIONS
2084 ######################################################################
2085 
2086 int slurm_set_trigger(slurm_t self, HV *trigger_info)
2087 	PREINIT:
2088 		trigger_info_t ti;
2089 	INIT:
2090 		if (self); /* this is needed to avoid a warning about
2091 			      unused variables.  But if we take slurm_t self
2092 			      out of the mix Slurm-> doesn't work,
2093 			      only Slurm::
2094 			    */
2095 	       if(hv_to_trigger_info(trigger_info, &ti) < 0) {
2096 			XSRETURN_UNDEF;
2097 		}
2098 	C_ARGS:
2099 		&ti
2100 
2101 int slurm_clear_trigger(slurm_t self, HV *trigger_info)
2102 	PREINIT:
2103 		trigger_info_t ti;
2104 	INIT:
2105 		if (self); /* this is needed to avoid a warning about
2106 			      unused variables.  But if we take slurm_t self
2107 			      out of the mix Slurm-> doesn't work,
2108 			      only Slurm::
2109 			    */
2110 		if(hv_to_trigger_info(trigger_info, &ti) < 0) {
2111 			XSRETURN_UNDEF;
2112 		}
2113 	C_ARGS:
2114 		&ti
2115 
2116 HV *
2117 slurm_get_triggers(slurm_t self)
2118 	PREINIT:
2119 		trigger_info_msg_t *ti_msg;
2120 		int rc;
2121 	CODE:
2122 		if (self); /* this is needed to avoid a warning about
2123 			      unused variables.  But if we take slurm_t self
2124 			      out of the mix Slurm-> doesn't work,
2125 			      only Slurm::
2126 			    */
2127 		rc = slurm_get_triggers(&ti_msg);
2128 		if(rc == SLURM_SUCCESS) {
2129 			RETVAL = newHV();
2130 			sv_2mortal((SV*)RETVAL);
2131 			rc = trigger_info_msg_to_hv(ti_msg, RETVAL);
2132 			slurm_free_trigger_msg(ti_msg);
2133 			if (rc < 0) {
2134 				XSRETURN_UNDEF;
2135 			}
2136 		} else {
2137 			XSRETURN_UNDEF;
2138 		}
2139 	OUTPUT:
2140 		RETVAL
2141 
2142 int
2143 slurm_pull_trigger(slurm_t self, HV *trigger_info)
2144 	PREINIT:
2145 		trigger_info_t ti;
2146 	INIT:
2147 		if (self); /* this is needed to avoid a warning about
2148 			      unused variables.  But if we take slurm_t self
2149 			      out of the mix Slurm-> doesn't work,
2150 			      only Slurm::
2151 			    */
2152 		if(hv_to_trigger_info(trigger_info, &ti) < 0) {
2153 			XSRETURN_UNDEF;
2154 		}
2155 	C_ARGS:
2156 		&ti
2157 
2158 ######################################################################
2159 #	SLURM HOSTLIST FUNCTIONS
2160 ######################################################################
2161 MODULE=Slurm PACKAGE=Slurm::Hostlist PREFIX=slurm_hostlist_
2162 
2163 hostlist_t
2164 slurm_hostlist_create(char* hostlist)
2165 
2166 int
2167 slurm_hostlist_count(hostlist_t hl)
2168 
2169 int
2170 slurm_hostlist_find(hostlist_t hl, char* hostname)
2171 
2172 int
2173 slurm_hostlist_push(hostlist_t hl, char* hosts)
2174 
2175 int
2176 slurm_hostlist_push_host(hostlist_t hl, char* host)
2177 
2178 char_xfree *
2179 slurm_hostlist_ranged_string(hostlist_t hl)
2180 	CODE:
2181 		RETVAL = slurm_hostlist_ranged_string_xmalloc(hl);
2182 		if (RETVAL == NULL) {
2183 			XSRETURN_UNDEF;
2184 		}
2185 	OUTPUT:
2186 		RETVAL
2187 
2188 char_free *
2189 slurm_hostlist_shift(hostlist_t hl = NULL)
2190 	CODE:
2191 		RETVAL = slurm_hostlist_shift(hl);
2192 		if (RETVAL == NULL) {
2193 			XSRETURN_UNDEF;
2194 		}
2195 	OUTPUT:
2196 		RETVAL
2197 
2198 void
2199 slurm_hostlist_uniq(hostlist_t hl)
2200 
2201 void
2202 slurm_hostlist_DESTROY(hostlist_t hl)
2203 	CODE:
2204 		slurm_hostlist_destroy(hl);
2205 
2206 
2207 # TODO: add some non-exported functions
2208 
2209 ######################################################################
2210 #	LIST FUNCTIONS
2211 ######################################################################
2212 MODULE = Slurm		PACKAGE = Slurm::List		PREFIX=slurm_list_
2213 
2214 #void
2215 #slurm_list_append(List l, void *x)
2216 
2217 int
2218 slurm_list_count(List l)
2219 
2220 int
2221 slurm_list_is_empty(List l)
2222 
2223 #List
2224 #slurm_list_create(ListDelF f)
2225 
2226 #void
2227 #slurm_list_sort(List l, ListCmpF f)
2228 
2229 void
2230 slurm_list_DESTROY(List l)
2231 	CODE:
2232 		slurm_list_destroy(l);
2233 
2234 ##################################################################################
2235 MODULE = Slurm		PACKAGE = Slurm::ListIterator	PREFIX=slurm_list_iterator_
2236 
2237 #void *
2238 #slurm_list_iterator_find(ListIterator i, ListFindF f, void *key)
2239 #	CODE:
2240 #		RETVAL = slurm_list_find(i, f, key)
2241 #	OUTPUT:
2242 #		RETVAL
2243 
2244 ListIterator
2245 slurm_list_iterator_create(List l)
2246 
2247 void
2248 slurm_list_iterator_reset(ListIterator i)
2249 
2250 #void *
2251 #slurm_list_iterator_next(ListIterator i)
2252 #	CODE:
2253 #		RETVAL = slurm_list_next(i)
2254 #	OUTPUT:
2255 #		RETVAL
2256 
2257 void
2258 slurm_list_iterator_DESTROY(ListIterator i)
2259 	CODE:
2260 		slurm_list_iterator_destroy(i);
2261 
2262 
2263 ######################################################################
2264 #	BITSTRING FUNCTIONS
2265 ######################################################################
2266 MODULE = Slurm		PACKAGE = Slurm::Bitstr	PREFIX=slurm_bit_
2267 #
2268 # $bitmap = Slurm::Bitstr::alloc($nbits);
2269 bitstr_t *
2270 slurm_bit_alloc(bitoff_t nbits)
2271 	POSTCALL:
2272 		if(RETVAL == NULL) {
2273 			XSRETURN_UNDEF;
2274 		}
2275 
2276 bitstr_t *
2277 slurm_bit_copy(bitstr_t *b)
2278 	POSTCALL:
2279 		if(RETVAL == NULL) {
2280 			XSRETURN_UNDEF;
2281 		}
2282 
2283 int
2284 slurm_bit_test(bitstr_t *b, bitoff_t bit)
2285 
2286 void
2287 slurm_bit_set(bitstr_t *b, bitoff_t bit)
2288 
2289 void
2290 slurm_bit_clear(bitstr_t *b, bitoff_t bit)
2291 
2292 void
2293 slurm_bit_nset(bitstr_t *b, bitoff_t start, bitoff_t stop)
2294 
2295 void
2296 slurm_bit_nclear(bitstr_t *b, bitoff_t start, bitoff_t stop)
2297 
2298 bitoff_t
2299 slurm_bit_ffc(bitstr_t *b)
2300 
2301 bitoff_t
2302 slurm_bit_ffs(bitstr_t *b)
2303 
2304 bitoff_t
2305 slurm_bit_fls(bitstr_t *b)
2306 
2307 bitoff_t
2308 slurm_bit_nffc(bitstr_t *b, int n)
2309 
2310 bitoff_t
2311 slurm_bit_nffs(bitstr_t *b, int n)
2312 
2313 bitoff_t
2314 slurm_bit_noc(bitstr_t *b, int n, int seed)
2315 
2316 bitoff_t
2317 slurm_bit_size(bitstr_t *b)
2318 
2319 void
2320 slurm_bit_and(bitstr_t *b1, bitstr_t *b2)
2321 
2322 void
2323 slurm_bit_not(bitstr_t *b)
2324 
2325 void
2326 slurm_bit_or(bitstr_t *b1, bitstr_t *b2)
2327 
2328 void
2329 slurm_bit_copybits(bitstr_t *b1, bitstr_t *b2)
2330 
2331 int
2332 slurm_bit_set_count(bitstr_t *b)
2333 
2334 int
2335 slurm_bit_set_count_range(bitstr_t *b, int start, int end)
2336 
2337 int
2338 slurm_bit_clear_count(bitstr_t *b)
2339 
2340 int
2341 slurm_bit_nset_max_count(bitstr_t *b)
2342 
2343 bitstr_t *
2344 slurm_bit_rotate_copy(bitstr_t *b, int n, bitoff_t nbits)
2345 	POSTCALL:
2346 		if(RETVAL == NULL) {
2347 			XSRETURN_UNDEF;
2348 		}
2349 
2350 void
2351 slurm_bit_rotate(bitstr_t *b, int n)
2352 
2353 
2354 # $str = $bitmap->fmt();
2355 char *
2356 slurm_bit_fmt(bitstr_t *b)
2357 	PREINIT:
2358 		int len = 1, bits;
2359 		char *tmp_str;
2360 	CODE:
2361 		bits = slurm_bit_size(b);
2362 		while(bits > 0) {
2363 			bits /= 10;
2364 			len ++;
2365 		}
2366 		bits = slurm_bit_size(b);
2367 		len *= bits;
2368 		New(0, tmp_str, len, char);
2369 		slurm_bit_fmt(tmp_str, len, b);
2370 		len = strlen(tmp_str) + 1;
2371 		New(0, RETVAL, len, char);
2372 		Copy(tmp_str, RETVAL, len, char);
2373 		Safefree(tmp_str);
2374 	OUTPUT:
2375 		RETVAL
2376 
2377 int
2378 slurm_bit_unfmt(bitstr_t *b, char *str)
2379 
2380 
2381 # $array = Slurm::Bitstr::fmt2int($str);
2382 AV *
2383 slurm_bit_fmt2int(char *str)
2384 	PREINIT:
2385 		int i = 0, *array;
2386 	CODE:
2387 		array = slurm_bitfmt2int(str);
2388 		RETVAL = newAV();
2389 		while (array[i] != -1) {
2390 			av_store_int(RETVAL, i, array[i]);
2391 			i ++;
2392 		}
2393 		xfree(array);
2394 	OUTPUT:
2395 		RETVAL
2396 
2397 
2398 char *
2399 slurm_bit_fmt_hexmask(bitstr_t *b)
2400 	PREINIT:
2401 		char *tmp_str;
2402 		int len;
2403 	CODE:
2404 		tmp_str = slurm_bit_fmt_hexmask(b);
2405 		len = strlen(tmp_str) + 1;
2406 		New(0, RETVAL, len, char);
2407 		Copy(tmp_str, RETVAL, len, char);
2408 		xfree(tmp_str);
2409 	OUTPUT:
2410 		RETVAL
2411 
2412 # XXX: only bits set in "str" are copied to "b".
2413 #      bits set originally in "b" stay set after unfmt.
2414 #      maybe this is a bug
2415 int
2416 slurm_bit_unfmt_hexmask(bitstr_t *b, char *str)
2417 
2418 char *
2419 slurm_bit_fmt_binmask(bitstr_t *b)
2420 	PREINIT:
2421 		char *tmp_str;
2422 		int len;
2423 	CODE:
2424 		tmp_str = slurm_bit_fmt_binmask(b);
2425 		len = strlen(tmp_str) + 1;
2426 		New(0, RETVAL, len, char);
2427 		Copy(tmp_str, RETVAL, len, char);
2428 		xfree(tmp_str);
2429 	OUTPUT:
2430 		RETVAL
2431 
2432 # ditto
2433 int
2434 slurm_bit_unfmt_binmask(bitstr_t *b, char *str)
2435 
2436 void
2437 slurm_bit_fill_gaps(bitstr_t *b)
2438 
2439 int
2440 slurm_bit_super_set(bitstr_t *b1, bitstr_t *b2)
2441 
2442 int
2443 slurm_bit_overlap(bitstr_t *b1, bitstr_t *b2)
2444 
2445 int
2446 slurm_bit_equal(bitstr_t *b1, bitstr_t *b2)
2447 
2448 bitstr_t *
2449 slurm_bit_pick_cnt(bitstr_t *b, bitoff_t nbits)
2450 	POSTCALL:
2451 		if(RETVAL == NULL) {
2452 			XSRETURN_UNDEF;
2453 		}
2454 
2455 bitoff_t
2456 slurm_bit_get_bit_num(bitstr_t *b, int pos)
2457 
2458 int
2459 slurm_bit_get_pos_num(bitstr_t *b, bitoff_t pos)
2460 
2461 void
2462 slurm_bit_DESTROY(bitstr_t *b)
2463 	CODE:
2464 		FREE_NULL_BITMAP(b);
2465