/*___INFO__MARK_BEGIN__*/ /************************************************************************* * * The Contents of this file are made available subject to the terms of * the Sun Industry Standards Source License Version 1.2 * * Sun Microsystems Inc., March, 2001 * * * Sun Industry Standards Source License Version 1.2 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.2 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2001 by Sun Microsystems, Inc. * * All Rights Reserved. * ************************************************************************/ /*___INFO__MARK_END__*/ #include #include #include #include "sge.h" #include "rmon/sgermon.h" #include "uti/sge_log.h" #include "uti/sge_htable.h" #include "uti/sge_stdlib.h" #include "uti/sge_prog.h" #include "uti/sge_parse_num_par.h" #include "comm/commlib.h" #include "cull/cull_list.h" #include "gdi/sge_gdi.h" #include "gdi/msg_gdilib.h" #include "sge_ja_task.h" #include "sge_pe_task.h" #include "sge_manop.h" #include "sge_range.h" #include "sge_var.h" #include "sge_path_alias.h" #include "sge_answer.h" #include "sge_object.h" #include "sge_pe.h" #include "sge_ckpt.h" #include "sge_centry.h" #include "sge_qinstance.h" #include "sge_host.h" #include "symbols.h" #include "sge_mesobj_QIM_L.h" #include "sge_advance_reservation.h" #include "sge_userset.h" #include "sge_qref.h" #include "sge_utility.h" #include "sgeobj/sge_binding.h" #include "msg_sgeobjlib.h" #include "msg_common.h" #include "sge_job.h" /****** sgeobj/job/job_get_ja_task_template_pending() ************************* * NAME * job_get_ja_task_template_pending() -- create a ja task template * * SYNOPSIS * lListElem* job_get_ja_task_template_pending(const lListElem *job, * u_long32 ja_task_id) * * FUNCTION * The function returns a pointer to a template array task element. * This task represents a currently submitted pending task * (no hold state). * * The task number (JAT_task_number) of this template task will be * initialized with the value given by 'ja_task_id'. * * INPUTS * const lListElem *job - JB_Type * u_long32 ja_task_id - array task number * * RESULT * lListElem* - template task (JAT_Type) * * SEE ALSO * sgeobj/job/job_get_ja_task_template_pending() * sgeobj/job/job_get_ja_task_template_hold() * sgeobj/job/job_get_ja_task_template() * * NOTES * MT-NOTE: job_get_ja_task_template_pending() is MT safe *******************************************************************************/ lListElem *job_get_ja_task_template_pending(const lListElem *job, u_long32 ja_task_id) { lListElem *template_task = NULL; /* JAT_Type */ DENTER(BASIS_LAYER, "job_get_ja_task_template"); template_task = lFirst(lGetList(job, JB_ja_template)); if (!template_task) { ERROR((SGE_EVENT, "unable to retrieve template task\n")); } else { lSetUlong(template_task, JAT_state, JQUEUED | JWAITING); lSetUlong(template_task, JAT_task_number, ja_task_id); } DRETURN(template_task); } /****** sgeobj/job/job_get_ja_task_template_hold() **************************** * NAME * job_get_ja_task_template_hold() -- create a ja task template * * SYNOPSIS * lListElem* job_get_ja_task_template_pending(const lListElem *job, * u_long32 ja_task_id) * * FUNCTION * The function returns a pointer to a template array task element. * This task represents a currently submitted pending task. * * The task number (JAT_task_number) of this template task will be * initialized with the value given by 'ja_task_id'. * * The hold state of the task (JAT_hold) will be initialized with * the 'hold_state' value. The function job_get_ja_task_hold_state() * may be used to get the current hold state of an unenrolled * pending task. * * INPUTS * const lListElem *job - JB_Type * u_long32 ja_task_id - array task number * * RESULT * lListElem* - template task (JAT_Type) * * SEE ALSO * sgeobj/job/job_get_ja_task_template_pending() * sgeobj/job/job_get_ja_task_hold_state() * sgeobj/job/job_get_ja_task_template() *******************************************************************************/ lListElem *job_get_ja_task_template_hold(const lListElem *job, u_long32 ja_task_id, u_long32 hold_state) { lListElem *template_task = NULL; /* JAT_Type */ DENTER(BASIS_LAYER, "job_get_ja_task_template"); template_task = job_get_ja_task_template_pending(job, ja_task_id); if (template_task) { u_long32 state; lSetUlong(template_task, JAT_task_number, ja_task_id); lSetUlong(template_task, JAT_hold, hold_state); lSetUlong(template_task, JAT_status, JIDLE); state = JQUEUED | JWAITING; if (lGetUlong(template_task, JAT_hold)) { state |= JHELD; } lSetUlong(template_task, JAT_state, state); } DRETURN(template_task); } /****** sgeobj/job/job_is_zombie_job() **************************************** * NAME * job_is_zombie_job() -- Is 'job' a zombie job * * SYNOPSIS * bool job_is_zombie_job(const lListElem *job) * * FUNCTION * True will be returned if 'job' is a zombie job. * * INPUTS * const lListElem *job - JB_Type * * RESULT * bool - true or false *******************************************************************************/ bool job_is_zombie_job(const lListElem *job) { return (lGetList(job, JB_ja_z_ids) != NULL ? true : false); } /****** sgeobj/job/job_get_ja_task_template() ********************************* * NAME * job_get_ja_task_template() -- create a ja task template * * SYNOPSIS * lListElem* job_get_ja_task_template_pending(const lListElem *job, * u_long32 ja_task_id) * * FUNCTION * The function returns a pointer to a template array task element. * This task represents a currently submitted pending task. * * INPUTS * const lListElem *job - JB_Type * u_long32 ja_task_id - array task number * * RESULT * lListElem* - template task (JAT_Type) * * SEE ALSO * sgeobj/job/job_get_ja_task_template_pending() * sgeobj/job/job_get_ja_task_template_hold() * sgeobj/job/job_get_ja_task_hold_state() * sgeobj/job/job_get_ja_task_template() *******************************************************************************/ lListElem *job_get_ja_task_template(const lListElem *job, u_long32 ja_task_id) { u_long32 hold_state = job_get_ja_task_hold_state(job, ja_task_id); return job_get_ja_task_template_hold(job, ja_task_id, hold_state); } /****** sgeobj/job/job_get_ja_task_hold_state() ******************************* * NAME * job_get_ja_task_hold_state() -- Hold state of unenrolled task * * SYNOPSIS * u_long32 job_get_ja_task_hold_state(const lListElem *job, * u_long32 ja_task_id) * * FUNCTION * Returns the hold state of a task which is not enrolled in * the JB_ja_tasks list of 'job' * * INPUTS * const lListElem *job - JB_Type * u_long32 ja_task_id - valid ja task id * * RESULT * u_long32 - hold state *******************************************************************************/ u_long32 job_get_ja_task_hold_state(const lListElem *job, u_long32 ja_task_id) { u_long32 ret = 0; DENTER(TOP_LAYER, "job_get_ja_task_hold_state"); if (range_list_is_id_within(lGetList(job, JB_ja_u_h_ids), ja_task_id)) { ret |= MINUS_H_TGT_USER; } if (range_list_is_id_within(lGetList(job, JB_ja_o_h_ids), ja_task_id)) { ret |= MINUS_H_TGT_OPERATOR; } if (range_list_is_id_within(lGetList(job, JB_ja_s_h_ids), ja_task_id)) { ret |= MINUS_H_TGT_SYSTEM; } if (range_list_is_id_within(lGetList(job, JB_ja_a_h_ids), ja_task_id)) { ret |= MINUS_H_TGT_JA_AD; } DRETURN(ret); } /****** sgeobj/job/job_create_hold_id_lists() ********************************* * NAME * job_create_hold_id_lists() -- Lists for hold combinations * * SYNOPSIS * void job_create_hold_id_lists(const lListElem *job, * lList *id_list[16], * u_long32 hold_state[16]) * * FUNCTION * This function creates sixteen 'id_lists'. Tasks whose id is * contained in an id list has the hold state combination delivered * by 'hold_state'. * * After using 'id_list' the function job_destroy_hold_id_lists() * has to be called to free allocated memory. * * INPUTS * const lListElem *job - JB_Type * lList *id_list[16] - NULL initialized pointer array * u_long32 hold_state[16] - Array for hold state combinations * * SEE ALSO * sgeobj/job/job_destroy_hold_id_lists() *******************************************************************************/ void job_create_hold_id_lists(const lListElem *job, lList *id_list[16], u_long32 hold_state[16]) { int i; lList *list[24]; DENTER(TOP_LAYER, "job_create_hold_id_lists"); hold_state[0] = 0; hold_state[1] = MINUS_H_TGT_USER; hold_state[2] = MINUS_H_TGT_OPERATOR; hold_state[3] = MINUS_H_TGT_SYSTEM; hold_state[4] = MINUS_H_TGT_JA_AD; hold_state[5] = MINUS_H_TGT_USER | MINUS_H_TGT_OPERATOR; hold_state[6] = MINUS_H_TGT_USER | MINUS_H_TGT_SYSTEM; hold_state[7] = MINUS_H_TGT_USER | MINUS_H_TGT_JA_AD; hold_state[8] = MINUS_H_TGT_OPERATOR | MINUS_H_TGT_SYSTEM; hold_state[9] = MINUS_H_TGT_OPERATOR | MINUS_H_TGT_JA_AD; hold_state[10] = MINUS_H_TGT_SYSTEM | MINUS_H_TGT_JA_AD; hold_state[11] = MINUS_H_TGT_USER | MINUS_H_TGT_OPERATOR | MINUS_H_TGT_SYSTEM; hold_state[12] = MINUS_H_TGT_USER | MINUS_H_TGT_OPERATOR | MINUS_H_TGT_JA_AD; hold_state[13] = MINUS_H_TGT_USER | MINUS_H_TGT_SYSTEM | MINUS_H_TGT_JA_AD; hold_state[14] = MINUS_H_TGT_OPERATOR | MINUS_H_TGT_SYSTEM | MINUS_H_TGT_JA_AD; hold_state[15] = MINUS_H_TGT_USER | MINUS_H_TGT_OPERATOR | MINUS_H_TGT_SYSTEM | MINUS_H_TGT_JA_AD; for (i = 0; i < 24; i++) { list[i] = NULL; } for (i = 0; i < 16; i++) { id_list[i] = NULL; } /* uo, us, ua, os, oa, sa, uos, uoa, usa, osa */ range_list_calculate_intersection_set(&list[0], NULL, lGetList(job, JB_ja_u_h_ids), lGetList(job, JB_ja_o_h_ids)); range_list_calculate_intersection_set(&list[1], NULL, lGetList(job, JB_ja_u_h_ids), lGetList(job, JB_ja_s_h_ids)); range_list_calculate_intersection_set(&list[2], NULL, lGetList(job, JB_ja_u_h_ids), lGetList(job, JB_ja_a_h_ids)); range_list_calculate_intersection_set(&list[3], NULL, lGetList(job, JB_ja_o_h_ids), lGetList(job, JB_ja_s_h_ids)); range_list_calculate_intersection_set(&list[4], NULL, lGetList(job, JB_ja_o_h_ids), lGetList(job, JB_ja_a_h_ids)); range_list_calculate_intersection_set(&list[5], NULL, lGetList(job, JB_ja_s_h_ids), lGetList(job, JB_ja_a_h_ids)); range_list_calculate_intersection_set(&list[6], NULL, list[0], list[3]); range_list_calculate_intersection_set(&list[7], NULL, list[0], list[4]); range_list_calculate_intersection_set(&list[8], NULL, list[1], list[5]); range_list_calculate_intersection_set(&list[9], NULL, list[3], list[5]); /* uosa -> 15 */ range_list_calculate_intersection_set(&id_list[15], NULL, list[6], list[7]); /* osaU -> 14 */ range_list_calculate_difference_set(&id_list[14], NULL, list[9], id_list[15]); /* usaO -> 13 */ range_list_calculate_difference_set(&id_list[13], NULL, list[8], id_list[15]); /* uoaS -> 12 */ range_list_calculate_difference_set(&id_list[12], NULL, list[7], id_list[15]); /* uosA -> 11 */ range_list_calculate_difference_set(&id_list[11], NULL, list[6], id_list[15]); /* saUO -> 10 */ range_list_calculate_difference_set(&list[10], NULL, list[5], list[8]); range_list_calculate_difference_set(&id_list[10], NULL, list[10], id_list[14]); /* oaUS -> 9 */ range_list_calculate_difference_set(&list[11], NULL, list[4], list[7]); range_list_calculate_difference_set(&id_list[9], NULL, list[11], id_list[14]); /* osUA -> 8 */ range_list_calculate_difference_set(&list[12], NULL, list[3], list[6]); range_list_calculate_difference_set(&id_list[8], NULL, list[12], id_list[14]); /* uaOS -> 7 */ range_list_calculate_difference_set(&list[13], NULL, list[2], list[7]); range_list_calculate_difference_set(&id_list[7], NULL, list[13], id_list[13]); /* usOA -> 6 */ range_list_calculate_difference_set(&list[14], NULL, list[1], list[6]); range_list_calculate_difference_set(&id_list[6], NULL, list[14], id_list[13]); /* uoSA -> 5 */ range_list_calculate_difference_set(&list[15], NULL, list[0], list[6]); range_list_calculate_difference_set(&id_list[5], NULL, list[15], id_list[12]); /* aUOS -> 4 */ range_list_calculate_difference_set(&list[16], NULL, lGetList(job, JB_ja_a_h_ids), list[2]); range_list_calculate_difference_set(&list[17], NULL, list[16], list[11]); range_list_calculate_difference_set(&id_list[4], NULL, list[17], id_list[10]); /* sUOA -> 3 */ range_list_calculate_difference_set(&list[18], NULL, lGetList(job, JB_ja_s_h_ids), list[1]); range_list_calculate_difference_set(&list[19], NULL, list[18], list[12]); range_list_calculate_difference_set(&id_list[3], NULL, list[19], id_list[10]); /* oUSA -> 2 */ range_list_calculate_difference_set(&list[20], NULL, lGetList(job, JB_ja_o_h_ids), list[0]); range_list_calculate_difference_set(&list[21], NULL, list[20], list[12]); range_list_calculate_difference_set(&id_list[2], NULL, list[21], id_list[9]); /* uOSA -> 1 */ range_list_calculate_difference_set(&list[22], NULL, lGetList(job, JB_ja_u_h_ids), list[0]); range_list_calculate_difference_set(&list[23], NULL, list[22], list[14]); range_list_calculate_difference_set(&id_list[1], NULL, list[23], id_list[7]); /* UOSA -> 0 */ id_list[0] = lCopyList("task_id_range", lGetList(job, JB_ja_n_h_ids)); for (i = 0; i < 24; i++) { lFreeList(&(list[i])); } DRETURN_VOID; } /****** sgeobj/job/job_destroy_hold_id_lists() ******************************** * NAME * job_destroy_hold_id_lists() -- destroy hold combination lists * * SYNOPSIS * void job_destroy_hold_id_lists(const lListElem *job, * lList *id_list[16]) * * FUNCTION * This function frees all memory allocated by a previous call of * job_create_hold_id_lists(). * * INPUTS * const lListElem *job - JB_Type * lList *id_list[16] - array of RN_Type lists * * SEE ALSO * sgeobj/job/job_create_hold_id_lists ******************************************************************************/ void job_destroy_hold_id_lists(const lListElem *job, lList *id_list[16]) { int i; DENTER(TOP_LAYER, "job_destroy_hold_id_lists"); for (i = 0; i < 16; i++) { lFreeList(&(id_list[i])); } DRETURN_VOID; } /****** sgeobj/job/job_is_enrolled() ****************************************** * NAME * job_is_enrolled() -- Is a certain array task enrolled * * SYNOPSIS * bool job_is_enrolled(const lListElem *job, u_long32 task_number) * * FUNCTION * This function will return true (1) if the array task with * 'task_number' is not enrolled in the JB_ja_tasks sublist * of 'job'. * * INPUTS * const lListElem *job - JB_Type * u_long32 task_number - task_number * * RESULT * bool - true or false ******************************************************************************/ bool job_is_enrolled(const lListElem *job, u_long32 task_number) { bool ret = true; DENTER(TOP_LAYER, "job_is_enrolled"); if (range_list_is_id_within(lGetList(job, JB_ja_n_h_ids), task_number) || range_list_is_id_within(lGetList(job, JB_ja_u_h_ids), task_number) || range_list_is_id_within(lGetList(job, JB_ja_o_h_ids), task_number) || range_list_is_id_within(lGetList(job, JB_ja_s_h_ids), task_number) || range_list_is_id_within(lGetList(job, JB_ja_a_h_ids), task_number)) { ret = false; } DRETURN(ret); } /****** sgeobj/job/job_is_ja_task_defined() *********************************** * NAME * job_is_ja_task_defined() -- was this task submitted * * SYNOPSIS * bool job_is_ja_task_defined(const lListElem *job, * u_long32 ja_task_number) * * FUNCTION * This function will return true (1) if the task with * 'ja_task_number' is defined within the array 'job'. The task * is defined when 'ja_task_number' is enclosed in the task id * range which was specified during submit time (qsub -t). * * INPUTS * const lListElem *job - JB_Type * u_long32 ja_task_number - task number * * RESULT * bool - true or false * * NOTES * MT-NOTE: job_is_ja_task_defined() is MT safe ******************************************************************************/ bool job_is_ja_task_defined(const lListElem *job, u_long32 ja_task_number) { lList *range_list = lGetList(job, JB_ja_structure); return range_list_is_id_within(range_list, ja_task_number); } /****** sgeobj/job/job_get_ja_tasks() ***************************************** * NAME * job_get_ja_tasks() -- returns number of array tasks * * SYNOPSIS * u_long32 job_get_ja_tasks(const lListElem *job) * * FUNCTION * This function returns the overall amount of tasks in an array job. * * INPUTS * const lListElem *job - JB_Type * * RESULT * u_long32 - number of tasks * * SEE ALSO * sgeobj/job/job_get_ja_tasks() * sgeobj/job/job_get_enrolled_ja_tasks() * sgeobj/job/job_get_not_enrolled_ja_tasks() * sgeobj/job/job_get_submit_ja_tasks() ******************************************************************************/ u_long32 job_get_ja_tasks(const lListElem *job) { u_long32 ret = 0; u_long32 n = 0; DENTER(TOP_LAYER, "job_get_ja_tasks"); n = job_get_not_enrolled_ja_tasks(job); ret += n; DPRINTF(("Not enrolled ja_tasks: "sge_u32"\n", n)); n = job_get_enrolled_ja_tasks(job); ret += n; DPRINTF(("Enrolled ja_tasks: "sge_u32"\n", n)); DRETURN(ret); } /****** sgeobj/job/job_get_not_enrolled_ja_tasks() **************************** * NAME * job_get_not_enrolled_ja_tasks() -- num. of unenrolled tasks * * SYNOPSIS * u_long32 job_get_not_enrolled_ja_tasks(const lListElem *job) * * FUNCTION * This function returns the amount of tasks not enrolled in the * JB_ja_tasks sublist. * * INPUTS * const lListElem *job - JB_Type * * RESULT * u_long32 - number of tasks * * SEE ALSO * sgeobj/job/job_get_ja_tasks() * sgeobj/job/job_get_enrolled_ja_tasks() * sgeobj/job/job_get_not_enrolled_ja_tasks() * sgeobj/job/job_get_submit_ja_tasks() ******************************************************************************/ u_long32 job_get_not_enrolled_ja_tasks(const lListElem *job) { lList *answer_list = NULL; lList *uosa_ids = NULL; lList *uos_ids = NULL; lList *uo_ids = NULL; u_long32 ret = 0; DENTER(TOP_LAYER, "job_get_not_enrolled_ja_tasks"); range_list_calculate_union_set(&uo_ids, &answer_list, lGetList(job, JB_ja_u_h_ids), lGetList(job, JB_ja_o_h_ids)); range_list_calculate_union_set(&uos_ids, &answer_list, uo_ids, lGetList(job, JB_ja_s_h_ids)); range_list_calculate_union_set(&uosa_ids, &answer_list, uos_ids, lGetList(job, JB_ja_a_h_ids)); ret += range_list_get_number_of_ids(lGetList(job, JB_ja_n_h_ids)); ret += range_list_get_number_of_ids(uosa_ids); lFreeList(&uosa_ids); lFreeList(&uos_ids); lFreeList(&uo_ids); DRETURN(ret); } /****** sgeobj/job/job_get_enrolled_ja_tasks() ******************************** * NAME * job_get_enrolled_ja_tasks() -- num. of enrolled array tasks * * SYNOPSIS * u_long32 job_get_not_enrolled_ja_tasks(const lListElem *job) * * FUNCTION * This function returns the amount of tasks enrolled in the * JB_ja_tasks sublist. * * INPUTS * const lListElem *job - JB_Type * * RESULT * u_long32 - number of tasks * * SEE ALSO * sgeobj/job/job_get_ja_tasks() * sgeobj/job/job_get_enrolled_ja_tasks() * sgeobj/job/job_get_not_enrolled_ja_tasks() * sgeobj/job/job_get_submit_ja_tasks() ******************************************************************************/ u_long32 job_get_enrolled_ja_tasks(const lListElem *job) { return lGetNumberOfElem(lGetList(job, JB_ja_tasks)); } /****** sgeobj/job/job_get_submit_ja_tasks() ********************************** * NAME * job_get_submit_ja_tasks() -- array size during job submittion * * SYNOPSIS * u_long32 job_get_submit_ja_tasks(const lListElem *job) * * FUNCTION * The function returns the ammount of tasks the job had during * it's submittion * * INPUTS * const lListElem *job - JB_Type * * RESULT * u_long32 - number of tasks * * SEE ALSO * sgeobj/job/job_get_ja_tasks() * sgeobj/job/job_get_enrolled_ja_tasks() * sgeobj/job/job_get_not_enrolled_ja_tasks() * sgeobj/job/job_get_submit_ja_tasks() ******************************************************************************/ u_long32 job_get_submit_ja_tasks(const lListElem *job) { u_long32 start, end, step; job_get_submit_task_ids(job, &start, &end, &step); return ((end - start) / step + 1); } /****** sgeobj/job/job_enroll() *********************************************** * NAME * job_enroll() -- enrolls a array task into the JB_ja_tasks lists * * SYNOPSIS * lListElem *job_enroll(lListElem *job, lList **answer_list, * u_long32 ja_task_number) * * FUNCTION * The task with 'ja_task_number' will be enrolled into the * JB_ja_tasks list of 'job' when this function is called. * * INPUTS * lListElem *job - JB_Type * lList **answer_list - AN_Type * u_long32 ja_task_number - task number * * RESULT * lListElem * - the ja_task * ******************************************************************************/ lListElem *job_enroll(lListElem *job, lList **answer_list, u_long32 ja_task_number) { lListElem *ja_task = NULL; DENTER(TOP_LAYER, "job_enroll"); object_delete_range_id(job, answer_list, JB_ja_n_h_ids, ja_task_number); ja_task = lGetSubUlong(job, JAT_task_number, ja_task_number, JB_ja_tasks); if (ja_task == NULL) { lListElem *template_task = NULL; lList *ja_task_list = lGetList(job, JB_ja_tasks); template_task = job_get_ja_task_template_pending(job, ja_task_number); if (ja_task_list == NULL) { ja_task_list = lCreateList("ulong_sublist", lGetElemDescr(template_task) ); lSetList(job, JB_ja_tasks, ja_task_list); } ja_task = lCopyElem(template_task); lAppendElem(ja_task_list, ja_task); } DRETURN(ja_task); } /****** sge_job/job_count_rescheduled_ja_tasks() ******************************* * NAME * job_count_rescheduled_ja_tasks() -- count rescheduled tasks * * SYNOPSIS * static int job_count_rescheduled_ja_tasks(lListElem *job, bool count_all) * * FUNCTION * Returns number of rescheduled tasks in JB_ja_tasks of a job. The * 'count_all' flag can be used to cause a quick exit if merely the * existence of rescheduled tasks is of interest. * * INPUTS * lListElem *job - the job (JB_Type) * bool count_all - quick exit flag * * RESULT * static int - number of tasks resp. 0/1 * * NOTES * MT-NOTE: job_count_rescheduled_ja_tasks() is MT safe *******************************************************************************/ static int job_count_rescheduled_ja_tasks(lListElem *job, bool count_all) { lListElem *ja_task; u_long32 state; int n = 0; for_each(ja_task, lGetList(job, JB_ja_tasks)) { state = lGetUlong(ja_task, JAT_state); if ((lGetUlong(ja_task, JAT_status) == JIDLE) && ((state & JQUEUED) != 0) && ((state & JWAITING) != 0)) { n++; if (!count_all) break; } } return n; } /****** sgeobj/job/job_count_pending_tasks() ******************************************** * NAME * job_count_pending_tasks() -- Count number of pending tasks * * SYNOPSIS * bool job_count_pending_tasks(lListElem *job, bool count_all) * * FUNCTION * This function returns the number of pending tasks of a job. * * INPUTS * lListElem *job - JB_Type * bool - number of tasks or simply 0/1 if count_all is 'false' * * RESULT * int - number of tasks or simply 0/1 if count_all is 'false' ******************************************************************************/ int job_count_pending_tasks(lListElem *job, bool count_all) { int n = 0; DENTER(TOP_LAYER, "job_count_pending_tasks"); if (count_all) { n = range_list_get_number_of_ids(lGetList(job, JB_ja_n_h_ids)); n += job_count_rescheduled_ja_tasks(job, true); } else { if (lGetList(job, JB_ja_n_h_ids) || job_count_rescheduled_ja_tasks(job, false)) n = 1; } DRETURN(n); } /****** sgeobj/job/job_delete_not_enrolled_ja_task() ************************** * NAME * job_delete_not_enrolled_ja_task() -- remove unenrolled task * * SYNOPSIS * void job_delete_not_enrolled_ja_task(lListElem *job, * lList **answer_list, * u_long32 ja_task_number) * * FUNCTION * Removes an unenrolled pending task from the id lists. * * INPUTS * lListElem *job - JB_Type * lList **answer_list - AN_Type * u_long32 ja_task_number - Task to be removed * * SEE ALSO * sgeobj/job/job_add_as_zombie() ******************************************************************************/ void job_delete_not_enrolled_ja_task(lListElem *job, lList **answer_list, u_long32 ja_task_number) { const int attributes = 5; const int attribute[] = {JB_ja_n_h_ids, JB_ja_u_h_ids, JB_ja_o_h_ids, JB_ja_s_h_ids, JB_ja_a_h_ids}; int i; DENTER(TOP_LAYER, "job_delete_not_enrolled_ja_task"); for (i = 0; i < attributes; i++) { object_delete_range_id(job, answer_list, attribute[i], ja_task_number); } DRETURN_VOID; } /****** sgeobj/job/job_add_as_zombie() **************************************** * NAME * job_add_as_zombie() -- add task into zombie id list * * SYNOPSIS * void job_add_as_zombie(lListElem *zombie, lList **answer_list, * u_long32 ja_task_id) * * FUNCTION * Adds a task into the zombie id list (JB_ja_z_ids) * * INPUTS * lListElem *zombie - JB_Type * lList **answer_list - AN_Type * u_long32 ja_task_id - Task id to be inserted * * SEE ALSO * sgeobj/job/job_delete_not_enrolled_ja_task() ******************************************************************************/ void job_add_as_zombie(lListElem *zombie, lList **answer_list, u_long32 ja_task_id) { lList *z_ids = NULL; /* RN_Type */ DENTER(TOP_LAYER, "job_add_as_zombie"); lXchgList(zombie, JB_ja_z_ids, &z_ids); range_list_insert_id(&z_ids, NULL, ja_task_id); range_list_compress(z_ids); lXchgList(zombie, JB_ja_z_ids, &z_ids); DRETURN_VOID; } /****** sgeobj/job/job_has_soft_requests() ******************************** * NAME * job_has_soft_requests() -- Has the job soft requests? * * SYNOPSIS * bool job_has_soft_requests(lListElem *job) * * FUNCTION * True (1) will be returned if the job has soft requests. * * INPUTS * lListElem *job - JB_Type * * RESULT * bool - true or false * * NOTES * MT-NOTES: job_has_soft_requests() is MT safe *******************************************************************************/ bool job_has_soft_requests(lListElem *job) { bool ret = false; if (lGetList(job, JB_soft_resource_list) != NULL || lGetList(job, JB_soft_queue_list) != NULL) { ret = true; } return ret; } /****** sgeobj/job/job_set_hold_state() *************************************** * NAME * job_set_hold_state() -- Changes the hold state of a task. * * SYNOPSIS * void job_set_hold_state(lListElem *job, lList **answer_list, * u_long32 ja_task_id, * u_long32 new_hold_state) * * FUNCTION * This function changes the hold state of a job/array-task. * * INPUTS * lListElem *job - JB_Type * lList **answer_list - AN_Type * u_long32 ja_task_id - Array task id * u_long32 new_hold_state - hold state (see MINUS_H_TGT_*) ******************************************************************************/ void job_set_hold_state(lListElem *job, lList **answer_list, u_long32 ja_task_id, u_long32 new_hold_state) { DENTER(TOP_LAYER, "job_set_hold_state"); if (!job_is_enrolled(job, ja_task_id)) { const int lists = 5; const u_long32 mask[] = {MINUS_H_TGT_ALL, MINUS_H_TGT_USER, MINUS_H_TGT_OPERATOR, MINUS_H_TGT_SYSTEM, MINUS_H_TGT_JA_AD}; const int attribute[] = {JB_ja_n_h_ids, JB_ja_u_h_ids, JB_ja_o_h_ids, JB_ja_s_h_ids, JB_ja_a_h_ids}; const range_remove_insert_t if_function[] = {range_list_remove_id, range_list_insert_id, range_list_insert_id, range_list_insert_id, range_list_insert_id}; const range_remove_insert_t else_function[] = {range_list_insert_id, range_list_remove_id, range_list_remove_id, range_list_remove_id, range_list_remove_id}; int i; for (i = 0; i < lists; i++) { lList *range_list = NULL; if (new_hold_state & mask[i]) { lXchgList(job, attribute[i], &range_list); if_function[i](&range_list, answer_list, ja_task_id); lXchgList(job, attribute[i], &range_list); } else { lXchgList(job, attribute[i], &range_list); else_function[i](&range_list, answer_list, ja_task_id); lXchgList(job, attribute[i], &range_list); } range_list_compress(lGetList(job, attribute[i])); } } else { lListElem *ja_task = job_search_task(job, NULL, ja_task_id); if (ja_task != NULL) { lSetUlong(ja_task, JAT_hold, new_hold_state); if (new_hold_state) { lSetUlong(ja_task, JAT_state, lGetUlong(ja_task, JAT_state) | JHELD); } else { lSetUlong(ja_task, JAT_state, lGetUlong(ja_task, JAT_state) & ~JHELD); } } } DRETURN_VOID; } /****** sgeobj/job/job_get_hold_state() *************************************** * NAME * job_get_hold_state() -- Returns the hold state of a task * * SYNOPSIS * u_long32 job_get_hold_state(lListElem *job, u_long32 ja_task_id) * * FUNCTION * Returns the hold state of a job/array-task * * INPUTS * lListElem *job - JB_Type * u_long32 ja_task_id - array task id * * RESULT * u_long32 - hold state (see MINUS_H_TGT_*) ******************************************************************************/ u_long32 job_get_hold_state(lListElem *job, u_long32 ja_task_id) { u_long32 ret = 0; DENTER(TOP_LAYER, "job_get_hold_state"); if (job_is_enrolled(job, ja_task_id)) { lListElem *ja_task = job_search_task(job, NULL, ja_task_id); if (ja_task != NULL) { ret = lGetUlong(ja_task, JAT_hold) & MINUS_H_TGT_ALL; } else { ret = 0; } } else { int attribute[4] = {JB_ja_u_h_ids, JB_ja_o_h_ids, JB_ja_s_h_ids, JB_ja_a_h_ids }; u_long32 hold_flag[4] = {MINUS_H_TGT_USER, MINUS_H_TGT_OPERATOR, MINUS_H_TGT_SYSTEM, MINUS_H_TGT_JA_AD}; int i; for (i = 0; i < 4; i++) { lList *hold_list = lGetList(job, attribute[i]); if (range_list_is_id_within(hold_list, ja_task_id)) { ret |= hold_flag[i]; } } } DRETURN(ret); } /****** sgeobj/job/job_search_task() ****************************************** * NAME * job_search_task() -- Search an array task * * SYNOPSIS * lListElem* job_search_task(const lListElem *job, * lList **answer_list, * u_long32 ja_task_id) * * FUNCTION * This function return the array task with the id 'ja_task_id' if * it exists in the JB_ja_tasks-sublist of 'job'. If the task * is not found in the sublist, NULL is returned. * * INPUTS * const lListElem *job - JB_Type * lList **answer_list - AN_Type * u_long32 ja_task_id - array task id * * RESULT * lListElem* - JAT_Type element * * NOTES * In case of errors, the function should return a message in a * given answer_list (answer_list != NULL). * MT-NOTE: job_search_task() is MT safe ******************************************************************************/ lListElem *job_search_task(const lListElem *job, lList **answer_list, u_long32 ja_task_id) { lListElem *ja_task = NULL; DENTER(TOP_LAYER, "job_search_task"); if (job != NULL) { ja_task = lGetSubUlong(job, JAT_task_number, ja_task_id, JB_ja_tasks); } DRETURN(ja_task); } /****** sgeobj/job/job_create_task() ****************************************** * NAME * job_create_task() -- Create an array task * * SYNOPSIS * lListElem* job_create_task(lListElem *job, lList **answer_list, * u_long32 ja_task_id) * * FUNCTION * This function return the array task with the id 'ja_task_id' if * it exists in the JB_ja_tasks-sublist of 'job'. * A new element will be created in the sublist * of 'job' and a pointer to the new element will be returned. * Errors may be found in the 'answer_list' * * INPUTS * lListElem *job - JB_Type * lList **answer_list - AN_Type * u_long32 ja_task_id - array task id * * RESULT * lListElem* - JAT_Type element * * NOTES * In case of errors, the function should return a message in a * given answer_list (answer_list != NULL). ******************************************************************************/ lListElem *job_create_task(lListElem *job, lList **answer_list, u_long32 ja_task_id) { lListElem *ja_task = NULL; DENTER(TOP_LAYER, "job_create_task"); if (job != NULL && job_is_ja_task_defined(job, ja_task_id)) { ja_task = job_enroll(job, answer_list, ja_task_id); } DRETURN(ja_task); } /****** sgeobj/job/job_get_shell_start_mode() ********************************* * NAME * job_get_shell_start_mode() -- get shell start mode for 'job' * * SYNOPSIS * const char* job_get_shell_start_mode(const lListElem *job, * const lListElem *queue, * const char *conf_shell_start_mode) * * FUNCTION * Returns a string identifying the shell start mode for 'job'. * * INPUTS * const lListElem *job - JB_Type element * const lListElem *queue - QU_Type element * const char *conf_shell_start_mode - shell start mode of * configuration * * RESULT * const char* - shell start mode ******************************************************************************/ const char *job_get_shell_start_mode(const lListElem *job, const lListElem *queue, const char *conf_shell_start_mode) { const char *ret; const char *queue_start_mode = lGetString(queue, QU_shell_start_mode); if (queue_start_mode && strcasecmp(queue_start_mode, "none")) { ret = queue_start_mode; } else { ret = conf_shell_start_mode; } return ret; } /****** sgeobj/job/job_list_add_job() ***************************************** * NAME * job_list_add_job() -- Creates a joblist and adds an job into it * * SYNOPSIS * int job_list_add_job(lList **job_list, const char *name, * lListElem *job, int check) * * FUNCTION * A 'job_list' will be created by this function if it does not * already exist and 'job' will be inserted into this 'job_list'. * 'name' will be the name of the new list. * * If 'check' is true (1) than the function will test whether * there is already an element in 'job_list' which has the same * 'JB_job_number' like 'job'. If this is true than -1 will be * returned by this function. * * * INPUTS * lList **job_list - JB_Type * const char *name - name of the list * lListElem *job - JB_Type element * int check - Does the element already exist? * * RESULT * int - error code * 1 => invalid parameter * -1 => check failed: element already exists * 0 => OK ******************************************************************************/ int job_list_add_job(lList **job_list, const char *name, lListElem *job, int check) { DENTER(TOP_LAYER, "job_list_add_job"); if (!job_list) { ERROR((SGE_EVENT, MSG_JOB_JLPPNULL)); DRETURN(1); } if (!job) { ERROR((SGE_EVENT, MSG_JOB_JEPNULL)); DRETURN(1); } if(!*job_list) { *job_list = lCreateList(name, JB_Type); } if (check && *job_list && job_list_locate(*job_list, lGetUlong(job, JB_job_number))) { dstring id_dstring = DSTRING_INIT; ERROR((SGE_EVENT, MSG_JOB_JOBALREADYEXISTS_S, job_get_id_string(lGetUlong(job, JB_job_number), 0, NULL, &id_dstring))); sge_dstring_free(&id_dstring); DRETURN(-1); } lAppendElem(*job_list, job); DRETURN(0); } /****** sgeobj/job/job_is_array() ********************************************* * NAME * job_is_array() -- Is "job" an array job or not? * * SYNOPSIS * bool job_is_array(const lListElem *job) * * FUNCTION * The function returns true (1) if "job" is an array job with more * than one task. * * INPUTS * const lListElem *job - JB_Type element * * RESULT * bool - true or false * * SEE ALSO * sgeobj/job/job_is_parallel() * sgeobj/job/job_is_tight_parallel() ******************************************************************************/ bool job_is_array(const lListElem *job) { u_long32 job_type = lGetUlong(job, JB_type); return JOB_TYPE_IS_ARRAY(job_type) ? true : false; } /****** sgeobj/job/job_is_parallel() ****************************************** * NAME * job_is_parallel() -- Is "job" a parallel job? * * SYNOPSIS * bool job_is_parallel(const lListElem *job) * * FUNCTION * This function returns true if "job" is a parallel job * (requesting a parallel environment). * * INPUTS * const lListELem *job - JB_Type element * * RESULT * bool - true or false * * SEE ALSO * sgeobj/job/job_is_array() * sgeobj/job/job_is_tight_parallel() ******************************************************************************/ bool job_is_parallel(const lListElem *job) { return (lGetString(job, JB_pe) != NULL ? true : false); } /****** sgeobj/job/job_is_tight_parallel() ************************************ * NAME * job_is_tight_parallel() -- Is "job" a tightly integrated par. job? * * SYNOPSIS * bool job_is_tight_parallel(const lListElem *job, * const lList *pe_list) * * FUNCTION * This function returns true if "job" is really a tightly * integrated parallel job. * * INPUTS * const lListElem *job - JB_Type element * const lList *pe_list - PE_Type list with all existing PEs * * RESULT * bool - true or false * * SEE ALSO * sgeobj/job/job_is_array() * sgeobj/job/job_is_parallel() * sgeobj/job/job_might_be_tight_parallel() ******************************************************************************/ bool job_is_tight_parallel(const lListElem *job, const lList *pe_list) { bool ret = false; const char *pe_name = NULL; DENTER(TOP_LAYER, "job_is_tight_parallel"); pe_name = lGetString(job, JB_pe); if (pe_name != NULL) { int found_pe = 0; int all_are_tight = 1; lListElem *pe; for_each(pe, pe_list) { if (pe_is_matching(pe, pe_name)) { found_pe = 1; all_are_tight &= lGetBool(pe, PE_control_slaves); } } if (found_pe && all_are_tight) { ret = true; } } DRETURN(ret); } /****** sgeobj/job/job_might_be_tight_parallel() ****************************** * NAME * job_might_be_tight_parallel() -- Tightly integrated job? * * SYNOPSIS * bool job_might_be_tight_parallel(const lListElem *job, * const lList *pe_list) * * FUNCTION * This functions returns true if "job" might be a tightly * integrated job. True will be returned if (at least one) pe * matching the requested (wildcard) pe of a job has * "contol_slaves=true" in its configuration. * * INPUTS * const lListElem *job - JB_Type element * const lList *pe_list - PE_Type list with all existing PEs * * RESULT * bool - true or false * * SEE ALSO * sgeobj/job/job_is_array() * sgeobj/job/job_is_parallel() * sgeobj/job/job_is_tight_parallel() * sgeobj/job/job_might_be_tight_parallel() ******************************************************************************/ bool job_might_be_tight_parallel(const lListElem *job, const lList *pe_list) { bool ret = false; const char *pe_name = NULL; DENTER(TOP_LAYER, "job_might_be_tight_parallel"); pe_name = lGetString(job, JB_pe); if (pe_name != NULL) { lListElem *pe; for_each(pe, pe_list) { if (pe_is_matching(pe, pe_name) && lGetBool(pe, PE_control_slaves)) { ret = true; break; } } } DRETURN(ret); } /****** sgeobj/job/job_get_submit_task_ids() ********************************** * NAME * job_get_submit_task_ids() -- Submit time task specification * * SYNOPSIS * void job_get_submit_task_ids(const lListElem *job, * u_long32 *start, * u_long32 *end, * u_long32 *step) * * FUNCTION * The function returns the "start", "end" and "step" numbers * which where used to create "job" (qsub -t ). * * INPUTS * const lListElem *job - JB_Type element * u_long32 *start - first id * u_long32 *end - last id * u_long32 *step - step size (>=1) ******************************************************************************/ void job_get_submit_task_ids(const lListElem *job, u_long32 *start, u_long32 *end, u_long32 *step) { lListElem *range_elem = NULL; /* RN_Type */ range_elem = lFirst(lGetList(job, JB_ja_structure)); if (range_elem) { u_long32 tmp_step; *start = lGetUlong(range_elem, RN_min); *end = lGetUlong(range_elem, RN_max); tmp_step = lGetUlong(range_elem, RN_step); *step = tmp_step ? tmp_step : 1; } else { *start = *end = *step = 1; } } /****** sgeobj/job/job_set_submit_task_ids() ********************************** * NAME * job_set_submit_task_ids() -- store the initial range ids in "job" * * SYNOPSIS * int job_set_submit_task_ids(lListElem *job, u_long32 start, * u_long32 end, u_long32 step) * * FUNCTION * The function stores the initial range id values ("start", "end" * and "step") in "job". It should only be used in functions * initializing new jobs. * * INPUTS * lListElem *job - JB_Type job * u_long32 start - first id * u_long32 end - last id * u_long32 step - step size * * RESULT * int - 0 -> OK * 1 -> no memory * * NOTES * MT-NOTE: job_set_submit_task_ids() is MT safe ******************************************************************************/ int job_set_submit_task_ids(lListElem *job, u_long32 start, u_long32 end, u_long32 step) { return object_set_range_id(job, JB_ja_structure, start, end, step); } /****** sgeobj/job/job_get_smallest_unenrolled_task_id() ********************** * NAME * job_get_smallest_unenrolled_task_id() -- get smallest id * * SYNOPSIS * u_long32 job_get_smallest_unenrolled_task_id(const lListElem *job) * * FUNCTION * Returns the smallest task id currently existing in a job * which is not enrolled in the JB_ja_tasks sublist of 'job'. * If all tasks are enrolled 0 will be returned. * * INPUTS * const lListElem *job - JB_Type element * * RESULT * u_long32 - task id or 0 ******************************************************************************/ u_long32 job_get_smallest_unenrolled_task_id(const lListElem *job) { u_long32 n_h_id, u_h_id, o_h_id, s_h_id, a_h_id; u_long32 ret = 0; n_h_id = range_list_get_first_id(lGetList(job, JB_ja_n_h_ids), NULL); u_h_id = range_list_get_first_id(lGetList(job, JB_ja_u_h_ids), NULL); o_h_id = range_list_get_first_id(lGetList(job, JB_ja_o_h_ids), NULL); s_h_id = range_list_get_first_id(lGetList(job, JB_ja_s_h_ids), NULL); a_h_id = range_list_get_first_id(lGetList(job, JB_ja_a_h_ids), NULL); ret = n_h_id; if (ret > 0 && u_h_id > 0) { ret = MIN(ret, u_h_id); } else if (u_h_id > 0) { ret = u_h_id; } if (ret > 0 && o_h_id > 0) { ret = MIN(ret, o_h_id); } else if (o_h_id > 0) { ret = o_h_id; } if (ret > 0 && s_h_id > 0) { ret = MIN(ret, s_h_id); } else if (s_h_id > 0){ ret = s_h_id; } if (ret == 0 && a_h_id > 0) { ret = MIN(ret, a_h_id); } else if (a_h_id > 0){ ret = a_h_id; } return ret; } /****** sgeobj/job/job_get_smallest_enrolled_task_id() ************************ * NAME * job_get_smallest_enrolled_task_id() -- find smallest enrolled tid * * SYNOPSIS * u_long32 job_get_smallest_enrolled_task_id(const lListElem *job) * * FUNCTION * Returns the smallest task id currently existing in a job * which is enrolled in the JB_ja_tasks sublist of 'job'. * If no task is enrolled 0 will be returned. * * INPUTS * const lListElem *job - JB_Type element * * RESULT * u_long32 - task id or 0 ******************************************************************************/ u_long32 job_get_smallest_enrolled_task_id(const lListElem *job) { lListElem *ja_task; /* JAT_Type */ lListElem *nxt_ja_task; /* JAT_Type */ u_long32 ret = 0; /* * initialize ret */ ja_task = lFirst(lGetList(job, JB_ja_tasks)); nxt_ja_task = lNext(ja_task); if (ja_task != NULL) { ret = lGetUlong(ja_task, JAT_task_number); } /* * try to find a smaller task id */ while ((ja_task = nxt_ja_task)) { nxt_ja_task = lNext(ja_task); ret = MIN(ret, lGetUlong(ja_task, JAT_task_number)); } return ret; } /****** sgeobj/job/job_get_biggest_unenrolled_task_id() *********************** * NAME * job_get_biggest_unenrolled_task_id() -- find biggest unenrolled id * * SYNOPSIS * u_long32 job_get_biggest_unenrolled_task_id(const lListElem *job) * * FUNCTION * Returns the biggest task id currently existing in a job * which is not enrolled in the JB_ja_tasks sublist of 'job'. * If no task is enrolled 0 will be returned. * * INPUTS * const lListElem *job - JB_Type element * * RESULT * u_long32 - task id or 0 ******************************************************************************/ u_long32 job_get_biggest_unenrolled_task_id(const lListElem *job) { u_long32 n_h_id, u_h_id, o_h_id, s_h_id, a_h_id; u_long32 ret = 0; n_h_id = range_list_get_last_id(lGetList(job, JB_ja_n_h_ids), NULL); u_h_id = range_list_get_last_id(lGetList(job, JB_ja_u_h_ids), NULL); o_h_id = range_list_get_last_id(lGetList(job, JB_ja_o_h_ids), NULL); s_h_id = range_list_get_last_id(lGetList(job, JB_ja_s_h_ids), NULL); a_h_id = range_list_get_last_id(lGetList(job, JB_ja_a_h_ids), NULL); ret = n_h_id; if (ret > 0 && u_h_id > 0) { ret = MAX(ret, u_h_id); } else if (u_h_id > 0) { ret = u_h_id; } if (ret > 0 && o_h_id > 0) { ret = MAX(ret, o_h_id); } else if (o_h_id > 0) { ret = o_h_id; } if (ret > 0 && s_h_id > 0) { ret = MAX(ret, s_h_id); } else if (s_h_id > 0 ){ ret = s_h_id; } if (ret == 0 && a_h_id > 0) { ret = MAX(ret, a_h_id); } else if (a_h_id > 0 ){ ret = a_h_id; } return ret; } /****** sgeobj/job/job_get_biggest_enrolled_task_id() ************************* * NAME * job_get_biggest_enrolled_task_id() -- find biggest enrolled tid * * SYNOPSIS * u_long32 job_get_biggest_enrolled_task_id(const lListElem *job) * * FUNCTION * Returns the biggest task id currently existing in a job * which is enrolled in the JB_ja_tasks sublist of 'job'. * If no task is enrolled 0 will be returned. * * INPUTS * const lListElem *job - JB_Type element * * RESULT * u_long32 - task id or 0 ******************************************************************************/ u_long32 job_get_biggest_enrolled_task_id(const lListElem *job) { lListElem *ja_task; /* JAT_Type */ lListElem *nxt_ja_task; /* JAT_Type */ u_long32 ret = 0; /* * initialize ret */ ja_task = lLast(lGetList(job, JB_ja_tasks)); nxt_ja_task = lPrev(ja_task); if (ja_task != NULL) { ret = lGetUlong(ja_task, JAT_task_number); } /* * try to find a smaller task id */ while ((ja_task = nxt_ja_task)) { nxt_ja_task = lPrev(ja_task); ret = MAX(ret, lGetUlong(ja_task, JAT_task_number)); } return ret; } /****** sgeobj/job/job_list_register_new_job() ******************************** * NAME * job_list_register_new_job() -- try to register a new job * * SYNOPSIS * int job_list_register_new_job(const lList *job_list, * u_long32 max_jobs) * * FUNCTION * This function checks whether a new job would exceed the maximum * of allowed jobs per cluster ("max_jobs"). If the limit would be * exceeded then the function will return 1 otherwise 0. In some * situations it may be necessary to force the registration * of a new job (reading jobs from spool area). This may be done * with "force_registration". * * * INPUTS * const lListElem *job - JB_Type element * u_long32 max_jobs - maximum number of allowed jobs per user * * RESULT * int - 1 => limit would be exceeded * 0 => otherwise * * SEE ALSO * sgeobj/suser/suser_register_new_job() ******************************************************************************/ int job_list_register_new_job(const lList *job_list, u_long32 max_jobs) { int ret = 1; DENTER(TOP_LAYER, "job_list_register_new_job"); if (max_jobs > 0 && max_jobs <= lGetNumberOfElem(job_list)) ret = 1; else ret = 0; DRETURN(ret); } /****** sgeobj/job/job_initialize_id_lists() ********************************** * NAME * job_initialize_id_lists() -- initialize task id range lists * * SYNOPSIS * void job_initialize_id_lists(lListElem *job, lList **answer_list) * * FUNCTION * Initialize the task id range lists within "job". All tasks within * the JB_ja_structure element of job will be added to the * JB_ja_n_h_ids list. All other id lists stored in the "job" will * be deleted. * * INPUTS * lListElem *job - JB_Type element * lList **answer_list - AN_Type list pointer * * RESULT * int - return state * -1 - error * 0 - OK * * SEE ALSO * sgeobj/range/RN_Type * * NOTES * MT-NOTE: job_initialize_id_lists() is MT safe ******************************************************************************/ int job_initialize_id_lists(lListElem *job, lList **answer_list) { lList *n_h_list = NULL; /* RN_Type */ DENTER(TOP_LAYER, "job_initialize_id_lists"); n_h_list = lCopyList("task_id_range", lGetList(job, JB_ja_structure)); if (n_h_list == NULL) { answer_list_add_sprintf(answer_list, STATUS_EMALLOC, ANSWER_QUALITY_ERROR, MSG_MEM_MEMORYALLOCFAILED_S, SGE_FUNC); DRETURN(-1); } else { lSetList(job, JB_ja_n_h_ids, n_h_list); lSetList(job, JB_ja_u_h_ids, NULL); lSetList(job, JB_ja_o_h_ids, NULL); lSetList(job, JB_ja_s_h_ids, NULL); lSetList(job, JB_ja_a_h_ids, NULL); } DRETURN(0); } /****** sgeobj/job/job_initialize_env() *************************************** * NAME * job_initialize_env() -- initialize environment (partially) * * SYNOPSIS * void job_initialize_env(lListElem *job, lList **answer_list, * const lList* path_alias_list) * * FUNCTION * Initialize the environment sublist (JB_env_list) of "job". * Path aliasing ("path_alias_list") has to be initialized before * this function might be called. * * Following enironment variables will be added: * O_HOME * O_LOGNAME * O_PATH * O_SHELL * O_TZ * O_HOST * O_WORKDIR * O_MAIL * * This function will be used in SGE/EE client applications. * Clients do not know which prefix should be used for job * environment variables ("SGE_" or other). Therefore * we use the define which will be replaced shortly * before the job is started. * * INPUTS * lListElem *job - JB_Type element * lList **answer_list - AN_Type list pointer * const lList* path_alias_list - PA_Type list ******************************************************************************/ void job_initialize_env(lListElem *job, lList **answer_list, const lList* path_alias_list, const char *unqualified_hostname, const char *qualified_hostname) { lList *env_list = NULL; dstring buffer = DSTRING_INIT; DENTER(TOP_LAYER, "job_initialize_env"); lXchgList(job, JB_env_list, &env_list); { int i = -1; const char* env_name[] = {"HOME", "LOGNAME", "PATH", "SHELL", "TZ", "MAIL", NULL}; while (env_name[++i] != NULL) { const char *env_value = sge_getenv(env_name[i]); sge_dstring_sprintf(&buffer, "%s%s%s", VAR_PREFIX, "O_", env_name[i]); var_list_set_string(&env_list, sge_dstring_get_string(&buffer), env_value); } } { const char* host = sge_getenv("HOST"); /* ??? */ if (host == NULL) { host = unqualified_hostname; } var_list_set_string(&env_list, VAR_PREFIX "O_HOST", host); } { char tmp_str[SGE_PATH_MAX + 1]; if (!getcwd(tmp_str, sizeof(tmp_str))) { answer_list_add(answer_list, MSG_ANSWER_GETCWDFAILED, STATUS_EDISK, ANSWER_QUALITY_ERROR); goto error; } path_alias_list_get_path(path_alias_list, NULL, tmp_str, qualified_hostname, &buffer); var_list_set_string(&env_list, VAR_PREFIX "O_WORKDIR", sge_dstring_get_string(&buffer)); } error: sge_dstring_free(&buffer); lXchgList(job, JB_env_list, &env_list); DRETURN_VOID; } /****** sgeobj/job/job_get_env_string() *************************************** * NAME * job_get_env_string() -- get value of certain job env variable * * SYNOPSIS * const char* job_get_env_string(const lListElem *job, * const char *variable) * * FUNCTION * Return the string value of the job environment "variable". * * Please note: The "*_O_*" env variables get their final * name shortly before job execution. Find more * information in the comment of * job_initialize_env() * * INPUTS * const lListElem *job - JB_Type element * const char* variable - environment variable name * * RESULT * const char* - value of "variable" * * SEE ALSO * sgeobj/job/job_initialize_env() * sgeobj/job/job_set_env_string() ******************************************************************************/ const char *job_get_env_string(const lListElem *job, const char *variable) { const char *ret = NULL; DENTER(TOP_LAYER, "job_get_env_value"); ret = var_list_get_string(lGetList(job, JB_env_list), variable); DRETURN(ret); } /****** sgeobj/job/job_set_env_string() *************************************** * NAME * job_set_env_string() -- set value of certain job env variable * * SYNOPSIS * void job_set_env_string(lListElem *job, * const char* variable, * const char *value) * * FUNCTION * Set the string "value" of the job environment "variable". * * Please note: The "*_O_*" env variables get their final * name shortly before job execution. Find more * information in the comment of * job_initialize_env() * * INPUTS * lListElem *job - JB_Type element * const char* variable - environment variable name * const char* value - new value * * SEE ALSO * sgeobj/job/job_initialize_env() * sgeobj/job/job_get_env_string() ******************************************************************************/ void job_set_env_string(lListElem *job, const char* variable, const char* value) { lList *env_list = NULL; DENTER(TOP_LAYER, "job_set_env_value"); lXchgList(job, JB_env_list, &env_list); var_list_set_string(&env_list, variable, value); lXchgList(job, JB_env_list, &env_list); DRETURN_VOID; } /****** sgeobj/job/job_check_correct_id_sublists() **************************** * NAME * job_check_correct_id_sublists() -- test JB_ja_* sublists * * SYNOPSIS * void * job_check_correct_id_sublists(lListElem *job, lList **answer_list) * * FUNCTION * Test following elements of "job" whether they are correct: * JB_ja_structure, JB_ja_n_h_ids, JB_ja_u_h_ids, * JB_ja_s_h_ids, JB_ja_o_h_ids, JB_ja_a_h_ids, JB_ja_z_ids * The function will try to correct errors within this lists. If * this is not possible an error will be returned in "answer_list". * * * INPUTS * lListElem *job - JB_Type element * lList **answer_list - AN_Type list * * RESULT * void - none ******************************************************************************/ void job_check_correct_id_sublists(lListElem *job, lList **answer_list) { DENTER(TOP_LAYER, "job_check_correct_id_sublists"); /* * Is 0 contained in one of the range lists */ { const int field[] = { JB_ja_structure, JB_ja_n_h_ids, JB_ja_u_h_ids, JB_ja_s_h_ids, JB_ja_o_h_ids, JB_ja_a_h_ids, JB_ja_z_ids, -1 }; int i = -1; while (field[++i] != -1) { lList *range_list = lGetList(job, field[i]); lListElem *range = NULL; for_each(range, range_list) { if (field[i] != JB_ja_structure) range_correct_end(range); if (range_is_id_within(range, 0)) { ERROR((SGE_EVENT, MSG_JOB_NULLNOTALLOWEDT)); answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); DRETURN_VOID; } } } } /* * JB_ja_structure and one of the JB_ja_?_h_ids has * to comprise at least one id. */ { const int field[] = { JB_ja_n_h_ids, JB_ja_u_h_ids, JB_ja_s_h_ids, JB_ja_o_h_ids, JB_ja_a_h_ids, -1 }; int has_structure = 0; int has_x_ids = 0; int i = -1; while (field[++i] != -1) { lList *range_list = lGetList(job, field[i]); if (!range_list_is_empty(range_list)) { has_x_ids = 1; } } has_structure = !range_list_is_empty(lGetList(job, JB_ja_structure)); if (!has_structure) { ERROR((SGE_EVENT, MSG_JOB_NOIDNOTALLOWED)); answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); DRETURN_VOID; } else if (!has_x_ids) { job_initialize_id_lists(job, answer_list); } } DRETURN_VOID; } /****** sgeobj/job/job_get_id_string() **************************************** * NAME * job_get_id_string() -- get an id string for a job/jatask/petask * * SYNOPSIS * const char * * job_get_id_string(u_long32 job_id, u_long32 ja_task_id, * const char *pe_task_id) * * FUNCTION * Returns an id string for a certain job, ja task or pe task. * The function should be used in any code that outputs ids, e.g. * in error strings to ensure we have the same output format * everywhere. If the ja_task_id is 0, only the job id is output. * * INPUTS * u_long32 job_id - the job id * u_long32 ja_task_id - the ja task id or 0 to output only * job_id * const char *pe_task_id - optionally the pe task id * dstring *buffer - a buffer to be used for printing the id string * * RESULT * const char* - pointer to a static buffer. It is valid until the * next call of the function. * * NOTES * MT-NOTE: job_get_id_string() is MT safe ******************************************************************************/ const char *job_get_id_string(u_long32 job_id, u_long32 ja_task_id, const char *pe_task_id, dstring *buffer) { DENTER(TOP_LAYER, "job_get_id_string"); if(job_id == 0) { sge_dstring_sprintf(buffer, ""); } else { if(ja_task_id == 0) { sge_dstring_sprintf(buffer, MSG_JOB_JOB_ID_U, job_id); } else { if(pe_task_id == NULL) { sge_dstring_sprintf(buffer, MSG_JOB_JOB_JATASK_ID_UU, job_id, ja_task_id); } else { sge_dstring_sprintf(buffer, MSG_JOB_JOB_JATASK_PETASK_ID_UUS, job_id, ja_task_id, pe_task_id); } } } DRETURN(sge_dstring_get_string(buffer)); } /****** sgeobj/job/job_is_pe_referenced() ************************************* * NAME * job_is_pe_referenced() -- Does job reference the given PE? * * SYNOPSIS * bool job_is_pe_referenced(const lListElem *job, * const lListElem *pe) * * FUNCTION * The function returns true if "job" references the "pe". * This is also the case if job requests a wildcard PE and * the wildcard name matches the given pe name. * * INPUTS * const lListElem *job - JB_Type element * const lListElem *pe - PE_Type object * * RESULT * int - true or false ******************************************************************************/ bool job_is_pe_referenced(const lListElem *job, const lListElem *pe) { const char *ref_pe_name = lGetString(job, JB_pe); bool ret = false; if(ref_pe_name != NULL) { if (pe_is_matching(pe, ref_pe_name)) { ret = true; } } return ret; } /****** sgeobj/job/job_is_ckpt_referenced() *********************************** * NAME * job_is_ckpt_referenced() -- Does job reference the given CKPT? * * SYNOPSIS * bool job_is_ckpt_referenced(const lListElem *job, * const lListELem *ckpt) * * FUNCTION * The function returns true if "job" references the * checkpointing object "ckpt". * * INPUTS * const lListElem *job - JB_Type element * const lListElem *ckpt - CK_Type object * * RESULT * bool - true or false ******************************************************************************/ bool job_is_ckpt_referenced(const lListElem *job, const lListElem *ckpt) { const char *ckpt_name = lGetString(ckpt, CK_name); const char *ref_ckpt_name = lGetString(job, JB_checkpoint_name); bool ret = false; if(ckpt_name != NULL && ref_ckpt_name != NULL) { if (!strcmp(ref_ckpt_name, ckpt_name)) { ret = true; } } return ret; } /****** sgeobj/job/job_get_state_string() ************************************* * NAME * job_get_state_string() -- write job state flags into a string * * SYNOPSIS * void job_get_state_string(char *str, u_long32 op) * * FUNCTION * This function writes the state flags given by 'op' into the * string 'str' * * INPUTS * char *str - containes the state flags for 'qstat'/'qhost' * u_long32 op - job state bitmask ******************************************************************************/ /* JG: TODO: use dstring! */ void job_get_state_string(char *str, u_long32 op) { int count = 0; DENTER(TOP_LAYER, "job_get_state_string"); if (VALID(JDELETED, op)) { str[count++] = DISABLED_SYM; } if (VALID(JERROR, op)) { str[count++] = ERROR_SYM; } if (VALID(JSUSPENDED_ON_SUBORDINATE, op) || VALID(JSUSPENDED_ON_SLOTWISE_SUBORDINATE, op)) { str[count++] = SUSPENDED_ON_SUBORDINATE_SYM; } if (VALID(JSUSPENDED_ON_THRESHOLD, op)) { str[count++] = SUSPENDED_ON_THRESHOLD_SYM; } if (VALID(JHELD, op)) { str[count++] = HELD_SYM; } if (VALID(JMIGRATING, op)) { str[count++] = RESTARTING_SYM; } if (VALID(JQUEUED, op)) { str[count++] = QUEUED_SYM; } if (VALID(JRUNNING, op)) { str[count++] = RUNNING_SYM; } if (VALID(JSUSPENDED, op)) { str[count++] = SUSPENDED_SYM; } if (VALID(JTRANSFERING, op)) { str[count++] = TRANSISTING_SYM; } if (VALID(JWAITING, op)) { str[count++] = WAITING_SYM; } if (VALID(JEXITING, op)) { str[count++] = EXITING_SYM; } str[count++] = '\0'; DEXIT; return; } /****** sgeobj/job/job_list_locate() ****************************************** * NAME * job_list_locate() -- find job in a list * * SYNOPSIS * lListElem* job_list_locate(lList *job_list, u_long32 job_id) * * FUNCTION * Returns the job element within "job_list" having "job_id" as * primary key. * * INPUTS * lList *job_list - JB_Type list * u_long32 job_id - job id * * RESULT * lListElem* - JB_Type element ******************************************************************************/ lListElem *job_list_locate(lList *job_list, u_long32 job_id) { lListElem *job = NULL; DENTER(BASIS_LAYER, "job_list_locate"); job = lGetElemUlong(job_list, JB_job_number, job_id); DRETURN(job); } /****** sgeobj/job/job_add_parent_id_to_context() ***************************** * NAME * job_add_parent_id_to_context() -- add parent jobid to job context * * SYNOPSIS * void job_add_parent_id_to_context(lListElem *job) * * FUNCTION * If we have JOB_ID in environment implicitly put it into the * job context variable PARENT if was not explicitly set using * "-sc PARENT=$JOBID". By doing this we preserve information * about the relationship between these two jobs. * * INPUTS * lListElem *job - JB_Type element * * RESULT * void - None ******************************************************************************/ void job_add_parent_id_to_context(lListElem *job) { lListElem *context_parent = NULL; /* VA_Type */ const char *job_id_string = NULL; job_id_string = sge_getenv("JOB_ID"); context_parent = lGetSubStr(job, VA_variable, CONTEXT_PARENT, JB_context); if (job_id_string != NULL && context_parent == NULL) { context_parent = lAddSubStr(job, VA_variable, CONTEXT_PARENT, JB_context, VA_Type); lSetString(context_parent, VA_value, job_id_string); } } /****** sgeobj/job/job_check_qsh_display() ************************************ * NAME * job_check_qsh_display() -- check DISPLAY variable for qsh jobs * * SYNOPSIS * int * job_check_qsh_display(const lListElem *job, lList **answer_list, * bool output_warning) * * FUNCTION * Checks the DISPLAY variable for qsh jobs: * - existence * - empty string * - local variable * * In each error cases, an appropriate error message is generated. * If output_warning is set to true, an error message is output. * In each case, an error message is written into answer_list. * * INPUTS * const lListElem *job - the job to check * lList **answer_list - answer list to take error messages, if * NULL, no answer is passed back. * bool output_warning - output error messages to stderr? * * RESULT * int - STATUS_OK, if function call succeeds, * else STATUS_EUNKNOWN. * * NOTES * To fully hide the data representation of the DISPLAY settings, * functions job_set_qsh_display and job_get_qsh_display would * be usefull. ******************************************************************************/ int job_check_qsh_display(const lListElem *job, lList **answer_list, bool output_warning) { const lListElem *display_ep; const char *display; DENTER(TOP_LAYER, "job_check_qsh_display"); /* check for existence of DISPLAY */ display_ep = lGetElemStr(lGetList(job, JB_env_list), VA_variable, "DISPLAY"); if(display_ep == NULL) { dstring id_dstring = DSTRING_INIT; if(output_warning) { WARNING((SGE_EVENT, MSG_JOB_NODISPLAY_S, job_get_id_string(lGetUlong(job, JB_job_number), 0, NULL, &id_dstring))); } else { sprintf(SGE_EVENT, MSG_JOB_NODISPLAY_S, job_get_id_string(lGetUlong(job, JB_job_number), 0, NULL, &id_dstring)); } answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); sge_dstring_free(&id_dstring); DRETURN(STATUS_EUNKNOWN); } /* check value of display variable, if it is an empty string, * it is useless in a grid environment. */ display = lGetString(display_ep, VA_value); if(display == NULL || strlen(display) == 0) { dstring id_dstring = DSTRING_INIT; if(output_warning) { WARNING((SGE_EVENT, MSG_JOB_EMPTYDISPLAY_S, job_get_id_string(lGetUlong(job, JB_job_number), 0, NULL, &id_dstring))); } else { sprintf(SGE_EVENT, MSG_JOB_EMPTYDISPLAY_S, job_get_id_string(lGetUlong(job, JB_job_number), 0, NULL, &id_dstring)); } answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); sge_dstring_free(&id_dstring); DRETURN(STATUS_EUNKNOWN); } /* check value of display variable, if it has the form : (local display) * it is useless in a grid environment. */ if(*display == ':') { dstring id_dstring = DSTRING_INIT; if(output_warning) { WARNING((SGE_EVENT, MSG_JOB_LOCALDISPLAY_SS, display, job_get_id_string(lGetUlong(job, JB_job_number), 0, NULL, &id_dstring))); } else { sprintf(SGE_EVENT, MSG_JOB_LOCALDISPLAY_SS, display, job_get_id_string(lGetUlong(job, JB_job_number), 0, NULL, &id_dstring)); } answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); sge_dstring_free(&id_dstring); DRETURN(STATUS_EUNKNOWN); } DRETURN(STATUS_OK); } /****** sgeobj/job/job_check_owner() ****************************************** * NAME * job_check_owner() -- check the owner of a job * * SYNOPSIS * int job_check_owner(const char *user_name, u_long32 job_id) * * FUNCTION * Checks if the owner of the job specified by job_id is the * user given by user_name. * * INPUTS * const char *user_name - the user name * u_long32 job_id - the job number * lList master_job_list - a ref to the master job list * * RESULT * int - -1, if the job cannot be found * 0, if the user is the job owner * 1, if the user is not the job owner ******************************************************************************/ int job_check_owner(const char *user_name, u_long32 job_id, lList *master_job_list) { lListElem *job; DENTER(TOP_LAYER, "job_check_owner"); if (!user_name) { DRETURN(-1); } if (manop_is_operator(user_name)) { DRETURN(0); } job = job_list_locate(master_job_list, job_id); if (job == NULL) { DRETURN(-1); } if (strcmp(user_name, lGetString(job, JB_owner)) != 0) { DRETURN(1); } DRETURN(0); } /****** sgeobj/job/job_get_job_key() ********************************************** * NAME * job_get_job_key() -- create a unique key * * SYNOPSIS * const char* job_get_job_key(u_long32 job_id) * * FUNCTION * Creates a unique key consisting of the job_id. * The job id can reread by calling job_parse_key(). * * INPUTS * u_long32 job_id - job id * * RESULT * const char* - pointer to a static buffer containing the key. * The result is only valid until the next call of the * function. * * NOTES * MT-NOTE: job_get_job_key() is MT safe * * SEE ALSO * sgeobj/job/job_get_key() * sgeobj/job/job_parse_key() ******************************************************************************/ const char *job_get_job_key(u_long32 job_id, dstring *buffer) { const char *ret = NULL; DENTER(TOP_LAYER, "job_get_job_key"); if (buffer != NULL) { ret = sge_dstring_sprintf(buffer, "%d", job_id); } DRETURN(ret); } /****** sgeobj/job/job_get_key() ********************************************** * NAME * job_get_key() -- create a unique key * * SYNOPSIS * const char* job_get_key(u_long32 job_id, u_long32 ja_task_id, * const char *pe_task_id) * * FUNCTION * Creates a unique key consisting of job_id, ja_task_id and * pe_task_id. This key can again be split into its components * by a call to job_parse_key(). * * INPUTS * u_long32 job_id - job id * u_long32 ja_task_id - ja task id * const char *pe_task_id - pe task id * * RESULT * const char* - pointer to a static buffer containing the key. * The result is only valid until the next call of the * function. * * NOTES * MT-NOTE: job_get_key() is MT safe * * SEE ALSO * sgeobj/job/job_parse_key() ******************************************************************************/ const char *job_get_key(u_long32 job_id, u_long32 ja_task_id, const char *pe_task_id, dstring *buffer) { const char *ret = NULL; DENTER(TOP_LAYER, "job_get_key"); if (buffer != NULL) { if (ja_task_id == 0) { ret = sge_dstring_sprintf(buffer, "%d", job_id); } else if (pe_task_id != NULL) { ret = sge_dstring_sprintf(buffer, "%d.%d %s", job_id, ja_task_id, pe_task_id); } else { ret = sge_dstring_sprintf(buffer, "%d.%d", job_id, ja_task_id); } } DRETURN(ret); } /****** sgeobj/job/job_parse_key() ******************************************** * NAME * job_parse_key() -- parse a key generated by job_get_key() * * SYNOPSIS * bool * job_parse_key(char *key, u_long32 *job_id, u_long32 *ja_task_id, * char **pe_task_id, bool *only_job) * * FUNCTION * Parse a key generated by job_get_key() and split it into its * components. * * INPUTS * char *key - key to be parsed * u_long32 *job_id - pointer to job_id * u_long32 *ja_task_id - pointer to ja_task_id * char **pe_task_id - pointer to pe_task_id * bool *only_job - true, if only a job id is contained in * key, else false. * * RESULT * bool - true, if the key could be parsed, else false * * NOTES * MT-NOTE: job_get_key() is MT safe * * The pe_task_id is only valid until the passed key is deleted! * * SEE ALSO * sgeobj/job/job_get_key() ******************************************************************************/ bool job_parse_key(char *key, u_long32 *job_id, u_long32 *ja_task_id, char **pe_task_id, bool *only_job) { const char *ja_task_id_str; char *lasts = NULL; DENTER(TOP_LAYER, "job_parse_key"); *job_id = atoi(strtok_r(key, ".", &lasts)); ja_task_id_str = strtok_r(NULL, " ", &lasts); if (ja_task_id_str == NULL) { *ja_task_id = 0; *pe_task_id = NULL; *only_job = true; } else { *ja_task_id = atoi(ja_task_id_str); *pe_task_id = strtok_r(NULL, " ", &lasts); *only_job = false; } if(*pe_task_id != NULL && strlen(*pe_task_id) == 0) { *pe_task_id = NULL; } DRETURN(true); } /****** sgeobj/job/jobscript_get_key() ********************************************** * NAME * jobscript_get_key() -- create a unique key * * SYNOPSIS * const char* jobscript_get_key(lListElem *jep, dstring *buffer) * * FUNCTION * Creates a unique key consisting of job_id and jobscript name * This key can again be split into its components * by a call to jobscript_parse_key() * * INPUTS * u_long32 job_id - job id * dstring *buffer - buffer * * RESULT * const char* - pointer to a static buffer containing the key. * * The result is only valid until the next call of the * function. * * NOTES * MT-NOTE: jobscript_get_key() is MT safe * * SEE ALSO * sgeobj/job/jobscript_parse_key() * ******************************************************************************/ const char *jobscript_get_key(lListElem *jep, dstring *buffer) { const char *ret = NULL; int job_id = lGetUlong(jep, JB_job_number); DENTER(TOP_LAYER, "jobscript_get_key"); if (buffer != NULL) { ret = sge_dstring_sprintf(buffer, "%s:%d.%s", object_type_get_name(SGE_TYPE_JOBSCRIPT), job_id, lGetString(jep, JB_exec_file)); } DRETURN(ret); } /****** sgeobj/job/jobscript_parse_key() ******************************************** * NAME * jobscript_parse_key() -- parse a key generated by job_get_key() * * SYNOPSIS * const char * job_parse_key(char *key, const char **exec_file) * * FUNCTION * Parse a key generated by jobscript_get_key() * * INPUTS * char *key - key to be parsed * onst char **exec_file - exec_file name to unlink * * RESULT * const char * the database job key * * NOTES * MT-NOTE: jobscript_parse_key() is MT safe * * * SEE ALSO * sgeobj/job/jobscript_get_key() ******************************************************************************/ char *jobscript_parse_key(char *key, const char **exec_file) { char *lasts = NULL; char *ret = NULL; DENTER(TOP_LAYER, "jobscript_parse_key"); ret = strtok_r(key, ".", &lasts); *exec_file = strtok_r(NULL, ".", &lasts); DRETURN(ret); } /****** sgeobj/job/job_resolve_host_for_path_list() *************************** * NAME * job_resolve_host_for_path_list() -- resolves hostnames in path lists * * SYNOPSIS * int * job_resolve_host_for_path_list(const lListElem *job, * lList **answer_list, int name) * * FUNCTION * Resolves hostnames in path lists. * * INPUTS * const lListElem *job - the submited cull list * lList **answer_list - AN_Type element * int name - a JB_Type (JB_stderr_path_list or * JB_stout_path_list) * * RESULT * int - error code (STATUS_OK, or ...) *******************************************************************************/ int job_resolve_host_for_path_list(const lListElem *job, lList **answer_list, int name) { bool ret_error=false; lListElem *ep; DENTER(TOP_LAYER, "job_resolve_host_for_path_list"); for_each(ep, lGetList(job, name)){ int res = sge_resolve_host(ep, PN_host); DPRINTF(("after sge_resolve_host() which returned %s\n", cl_get_error_text(res))); if (res != CL_RETVAL_OK) { const char *hostname = lGetHost(ep, PN_host); if (hostname != NULL) { ERROR((SGE_EVENT, MSG_SGETEXT_CANTRESOLVEHOST_S, hostname)); answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); ret_error=true; } else if (res != CL_RETVAL_PARAMS) { ERROR((SGE_EVENT,MSG_PARSE_NULLPOINTERRECEIVED )); answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); ret_error=true; } } DPRINTF(("after sge_resolve_host() - II\n")); /* ensure, that each hostname is only specified once */ if( !ret_error ){ const char *hostname = lGetHost(ep, PN_host); lListElem *temp; for(temp= lPrev(ep); temp; temp =lPrev(temp)){ const char *temp_hostname = lGetHost(temp, PN_host); if(hostname == NULL){ if(temp_hostname == NULL){ ERROR((SGE_EVENT, MSG_PARSE_DUPLICATEHOSTINFILESPEC)); answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); ret_error=true; } } else if( temp_hostname && strcmp(hostname, temp_hostname)==0){ ERROR((SGE_EVENT, MSG_PARSE_DUPLICATEHOSTINFILESPEC)); answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); ret_error=true; } if(ret_error) break; }/* end for */ } if(ret_error) { break; } }/*end for*/ if(ret_error) { DRETURN(STATUS_EUNKNOWN); } else { DRETURN(STATUS_OK); } } /****** sgeobj/job/job_get_request() ****************************************** * NAME * job_get_request() -- Returns the requested centry name * * SYNOPSIS * lListElem * * job_get_request(const lListElem *this_elem, const char **centry_name) * * FUNCTION * Returns the requested centry name if it is requested by the give * job (JB_Type). * * INPUTS * const lListElem *this_elem - JB_Type element * const char *centry_name - name * * RESULT * lListElem * - CE_Type element * * NOTES * MT-NOTE: job_get_request() is MT safe *******************************************************************************/ lListElem * job_get_request(const lListElem *this_elem, const char *centry_name) { lList *hard_centry_list = NULL; lListElem *ret = NULL; DENTER(TOP_LAYER, "job_get_request"); hard_centry_list = lGetList(this_elem, JB_hard_resource_list); ret = lGetElemStr(hard_centry_list, CE_name, centry_name); if (ret == NULL) { lList *soft_centry_list = lGetList(this_elem, JB_soft_resource_list); ret = lGetElemStr(soft_centry_list, CE_name, centry_name); } DRETURN(ret); } /* EB: ADOC: add commets */ bool job_get_contribution(const lListElem *this_elem, lList **answer_list, const char *name, double *value, const lListElem *implicit_centry) { bool ret = true; lListElem *centry = NULL; const char *value_string = NULL; char error_str[256]; DENTER(TOP_LAYER, "job_get_contribution"); centry = job_get_request(this_elem, name); if (centry != NULL) { value_string = lGetString(centry, CE_stringval); } if (value_string == NULL) { value_string = lGetString(implicit_centry, CE_default); } if (!(parse_ulong_val(value, NULL, TYPE_INT, value_string, error_str, sizeof(error_str)-1))) { answer_list_add_sprintf(answer_list, STATUS_EEXIST, ANSWER_QUALITY_ERROR, MSG_ATTRIB_PARSATTRFAILED_SS, name, error_str); ret = false; } DRETURN(ret); } /****** sge_job/sge_unparse_acl_dstring() ************************************** * NAME * sge_unparse_acl_dstring() -- creates a string from the access lists and user * * SYNOPSIS * bool sge_unparse_acl_dstring(dstring *category_str, const char *owner, * const char *group, const lList *acl_list, const char *option) * * FUNCTION * ??? * * INPUTS * dstring *category_str - target string * const char *owner - job owner * const char *group - group owner * const lList *acl_list - a list of all access lists * const char *option - string option to put in infront of the generated string * * RESULT * bool - true, if everything was fine * * NOTES * MT-NOTE: sge_unparse_acl_dstring() is MT safe * *******************************************************************************/ bool sge_unparse_acl_dstring(dstring *category_str, const char *owner, const char *group, const lList *acl_list, const char *option) { bool first = true; const lListElem *elem = NULL; DENTER(TOP_LAYER, "sge_unparse_acl_dstring"); for_each (elem, acl_list) { if (lGetBool(elem, US_consider_with_categories) && sge_contained_in_access_list(owner, group, elem, NULL)) { if (first) { if (sge_dstring_strlen(category_str) > 0) { sge_dstring_append_char(category_str, ' '); } sge_dstring_append(category_str, option); sge_dstring_append_char(category_str, ' '); sge_dstring_append(category_str, lGetString(elem, US_name)); first = false; } else { sge_dstring_append_char(category_str, ','); sge_dstring_append(category_str, lGetString(elem, US_name)); } } } DRETURN(true); } /****** sge_job/sge_unparse_queue_list_dstring() ******************************* * NAME * sge_unparse_queue_list_dstring() -- creates a string from a queue name list * * SYNOPSIS * bool sge_unparse_queue_list_dstring(dstring *category_str, const * lListElem *job_elem, int nm, const char *option) * * FUNCTION * ??? * * INPUTS * dstring *category_str - target string * const lListElem *job_elem - a job structure * int nm - position in of the queue list attribute in the job * const char *option - string option to put in infront of the generated string * * RESULT * bool - true, if everything was fine * * NOTES * MT-NOTE: sge_unparse_queue_list_dstring() is MT safe * *******************************************************************************/ bool sge_unparse_queue_list_dstring(dstring *category_str, lListElem *job_elem, int nm, const char *option) { bool first = true; lList *print_list = NULL; const lListElem *sub_elem = NULL; DENTER(TOP_LAYER, "sge_unparse_queue_list_dstring"); if ((print_list = lGetPosList(job_elem, nm)) != NULL) { lPSortList(print_list, "%I+", QR_name); for_each (sub_elem, print_list) { if (first) { if (sge_dstring_strlen(category_str) > 0) { sge_dstring_append_char(category_str, ' '); } sge_dstring_append(category_str, option); sge_dstring_append_char(category_str, ' '); sge_dstring_append(category_str, lGetString(sub_elem, QR_name)); first = false; } else { sge_dstring_append_char(category_str, ','); sge_dstring_append(category_str, lGetString(sub_elem, QR_name)); } } } DRETURN(true); } /****** sge_job/sge_unparse_resource_list_dstring() **************************** * NAME * sge_unparse_resource_list_dstring() -- creates a string from resource requests * * SYNOPSIS * bool sge_unparse_resource_list_dstring(dstring *category_str, lListElem * *job_elem, int nm, const char *option) * * FUNCTION * ??? * * INPUTS * dstring *category_str - target string * lListElem *job_elem - a job structure * int nm - position of the resource list attribute in the job * const char *option - string option to put in infront of the generated string * * RESULT * bool - true, if everything was fine * * NOTES * MT-NOTE: sge_unparse_resource_list_dstring() is MT safe * *******************************************************************************/ bool sge_unparse_resource_list_dstring(dstring *category_str, lListElem *job_elem, int nm, const char *option) { bool first = true; lList *print_list = NULL; const lListElem *sub_elem = NULL; DENTER(TOP_LAYER, "sge_unparse_resource_list_dstring"); if ((print_list = lGetPosList(job_elem, nm)) != NULL) { lPSortList(print_list, "%I+", CE_name); for_each (sub_elem, print_list) { if (first) { if (sge_dstring_strlen(category_str) > 0) { sge_dstring_append(category_str, " "); } sge_dstring_append(category_str, option); sge_dstring_append(category_str, " "); sge_dstring_append(category_str, lGetString(sub_elem, CE_name)); sge_dstring_append(category_str, "="); sge_dstring_append(category_str, lGetString(sub_elem, CE_stringval)); first = false; } else { sge_dstring_append(category_str, ","); sge_dstring_append(category_str, lGetString(sub_elem, CE_name)); sge_dstring_append(category_str, "="); sge_dstring_append(category_str, lGetString(sub_elem, CE_stringval)); } } } DRETURN(true); } /****** sge_job/sge_unparse_pe_dstring() *************************************** * NAME * sge_unparse_pe_dstring() -- creates a string from a pe request * * SYNOPSIS * bool sge_unparse_pe_dstring(dstring *category_str, const lListElem * *job_elem, int pe_pos, int range_pos, const char *option) * * FUNCTION * ??? * * INPUTS * dstring *category_str - target string * const lListElem *job_elem - a job structure * int pe_pos - position of the pe name attribute in the job * int range_pos - position of the pe range request attribute in the job * const char *option - string option to put in infront of the generated string * * RESULT * bool - true, if everything was fine * * NOTES * MT-NOTE: sge_unparse_pe_dstring() is MT safe * *******************************************************************************/ bool sge_unparse_pe_dstring(dstring *category_str, const lListElem *job_elem, int pe_pos, int range_pos, const char *option) { const lList *range_list = NULL; DENTER(TOP_LAYER, "sge_unparse_pe_dstring"); if (lGetPosString(job_elem, pe_pos) != NULL) { if ((range_list = lGetPosList(job_elem, range_pos)) == NULL) { DPRINTF(("Job has parallel environment with no ranges\n")); DRETURN(false); } else { dstring range_string = DSTRING_INIT; range_list_print_to_string(range_list, &range_string, true, false, false); if (sge_dstring_strlen(category_str) > 0) { sge_dstring_append(category_str, " "); } sge_dstring_append(category_str, option); sge_dstring_append(category_str, " "); sge_dstring_append(category_str, lGetString(job_elem, JB_pe)); sge_dstring_append(category_str, " "); sge_dstring_append_dstring(category_str, &range_string); sge_dstring_free(&range_string); } } DRETURN(true); } /****** sge_job/sge_unparse_string_option_dstring() **************************** * NAME * sge_unparse_string_option_dstring() -- copies a string into a dstring * * SYNOPSIS * bool sge_unparse_string_option_dstring(dstring *category_str, const * lListElem *job_elem, int nm, char *option) * * FUNCTION * Copies a string into a dstring. Used for category string building * * INPUTS * dstring *category_str - target string * const lListElem *job_elem - a job structure * int nm - position of the string attribute in the job * char *option - string option to put in in front of the generated string * * RESULT * bool - always true * * NOTES * MT-NOTE: sge_unparse_string_option_dstring() is MT safe * * SEE ALSO * sge_job/sge_unparse_ulong_option_dstring() *******************************************************************************/ bool sge_unparse_string_option_dstring(dstring *category_str, const lListElem *job_elem, int nm, char *option) { const char *string = NULL; DENTER(TOP_LAYER, "sge_unparse_string_option_dstring"); if ((string = lGetPosString(job_elem, nm)) != NULL) { if (sge_dstring_strlen(category_str) > 0) { sge_dstring_append(category_str, " "); } sge_dstring_append(category_str, option); sge_dstring_append(category_str, " "); sge_dstring_append(category_str, string); } DRETURN(true); } /****** sge_job/sge_unparse_ulong_option_dstring() ***************************** * NAME * sge_unparse_ulong_option_dstring() -- copies a string into a dstring * * SYNOPSIS * bool sge_unparse_ulong_option_dstring(dstring *category_str, const * lListElem *job_elem, int nm, char *option) * * FUNCTION * Copies a string into a dstring. Used for category string building * * INPUTS * dstring *category_str - target string * const lListElem *job_elem - a job structure * int nm - position of the string attribute in the job * char *option - string option to put in front of the generated string * * RESULT * bool - always true * * EXAMPLE * ??? * * NOTES * MT-NOTE: sge_unparse_ulong_option_dstring() is MT safe * * SEE ALSO * sge_job/sge_unparse_string_option_dstring() *******************************************************************************/ bool sge_unparse_ulong_option_dstring(dstring *category_str, const lListElem *job_elem, int nm, char *option) { u_long32 ul = 0; DENTER(TOP_LAYER, "sge_unparse_ulong_option_dstring"); if ((ul = lGetPosUlong(job_elem, nm)) != 0) { if (sge_dstring_strlen(category_str) > 0) { sge_dstring_append(category_str, " "); } sge_dstring_append(category_str, option); sge_dstring_append(category_str, " "); sge_dstring_sprintf_append(category_str, sge_U32CFormat, ul); } DRETURN(true); } /****** sge_job/job_verify() *************************************************** * NAME * job_verify() -- verify a job object * * SYNOPSIS * bool * job_verify(const lListElem *job, lList **answer_list) * * FUNCTION * Verifies structure and contents of a job object. * As a job object may look quite different depending on its state, * additional functions are provided, calling this function doing * general tests and doing additional verification themselves. * * INPUTS * const lListElem *job - the job object to verify * lList **answer_list - answer list to pass back error messages * bool do_cull_verify - do cull verification against the JB_Type descriptor. * * RESULT * bool - true on success, * false on error with error message in answer_list * * NOTES * MT-NOTE: job_verify() is MT safe * * BUGS * The function is far from being complete. * Currently, only the CULL structure is verified, not the contents. * * SEE ALSO * sge_object/object_verify_cull() * sge_job/job_verify_submitted_job() * sge_job/job_verify_execd_job() *******************************************************************************/ bool job_verify(const lListElem *job, lList **answer_list, bool do_cull_verify) { bool ret = true; DENTER(TOP_LAYER, "job_verify"); if (job == NULL) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_NULLELEMENTPASSEDTO_S, "job_verify"); DRETURN(false); } if (ret && do_cull_verify) { if (!object_verify_cull(job, JB_Type)) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_OBJECT_STRUCTURE_ERROR); ret = false; } } if (ret) { const char *name = lGetString(job, JB_job_name); if (name != NULL) { if (strlen(name) >= MAX_VERIFY_STRING) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_JOB_NAMETOOLONG_I, MAX_VERIFY_STRING); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_JOB_NOJOBNAME); ret = false; } } if (ret) { const char *cwd = lGetString(job, JB_cwd); if (cwd != NULL) { /* * cwd needn't be an absolute path, we also accept * relative paths, e.g. via -wd switch, * or even pseudo variables, e.g. $HOME used by drmaa submit */ ret = path_verify(cwd, answer_list, "cwd", false); } } if (ret) { const lList *path_aliases = lGetList(job, JB_path_aliases); if (path_aliases != NULL) { ret = path_alias_verify(path_aliases, answer_list); } } if (ret) { const lList *env_list = lGetList(job, JB_env_list); if (env_list != NULL) { ret = var_list_verify(env_list, answer_list); } } if (ret) { const lList *context_list = lGetList(job, JB_context); if (context_list != NULL) { ret = var_list_verify(context_list, answer_list); } } if (ret) { ret = path_list_verify(lGetList(job, JB_stdout_path_list), answer_list, "stdout path"); } if (ret) { ret = path_list_verify(lGetList(job, JB_stderr_path_list), answer_list, "stderr path"); } if (ret) { ret = path_list_verify(lGetList(job, JB_stdin_path_list), answer_list, "stdin path"); } DRETURN(ret); } /****** sge_job/job_verify_submitted_job() ************************************* * NAME * job_verify_submitted_job() -- verify a just submitted job * * SYNOPSIS * bool * job_verify_submitted_job(const lListElem *job, lList **answer_list) * * FUNCTION * Verifies a just submitted job object. * Does generic tests by calling job_verify, like verifying the cull * structure, and makes sure a number of job attributes are set * correctly. * * INPUTS * const lListElem *job - the job to verify * lList **answer_list - answer list to pass back error messages * * RESULT * bool - true on success, * false on error with error message in answer_list * * NOTES * MT-NOTE: job_verify_submitted_job() is MT safe * * BUGS * The function is far from being complete. * Currently, only the CULL structure is verified, not the contents. * * SEE ALSO * sge_job/job_verify() *******************************************************************************/ bool job_verify_submitted_job(const lListElem *job, lList **answer_list) { bool ret = true; DENTER(TOP_LAYER, "job_verify_submitted_job"); ret = job_verify(job, answer_list, true); /* JB_job_number must me 0 */ if (ret) { ret = object_verify_ulong_null(job, answer_list, JB_job_number); } /* JB_version must be 0 */ if (ret) { ret = object_verify_ulong_null(job, answer_list, JB_version); } /* TODO: JB_jid_request_list */ /* TODO: JB_jid_predecessor_l */ /* TODO: JB_jid_sucessor_list */ /* JB_session must be a valid string */ if (ret) { const char *name = lGetString(job, JB_session); if (name != NULL) { if (verify_str_key( answer_list, name, MAX_VERIFY_STRING, lNm2Str(JB_session), KEY_TABLE) != STATUS_OK) { ret = false; } } } /* JB_project must be a valid string */ if (ret) { const char *name = lGetString(job, JB_project); if (name != NULL) { if (verify_str_key( answer_list, name, MAX_VERIFY_STRING, lNm2Str(JB_project), KEY_TABLE) != STATUS_OK) { ret = false; } } } /* JB_department must be a valid string */ if (ret) { const char *name = lGetString(job, JB_department); if (name != NULL) { if (verify_str_key( answer_list, name, MAX_VERIFY_STRING, lNm2Str(JB_department), KEY_TABLE) != STATUS_OK) { ret = false; } } } /* TODO: JB_directive_prefix can be any string, verify_str_key is too restrictive */ /* JB_exec_file must be a valid directory string */ if (ret) { const char *name = lGetString(job, JB_exec_file); if (name != NULL) { ret = path_verify(name, answer_list, "exec_file", false); } } /* JB_script_file must be a string and a valid directory string */ if (ret) { const char *name = lGetString(job, JB_script_file); if (name != NULL) { ret = path_verify(name, answer_list, "script_file", false); } } /* JB_script_ptr must be any string */ if (ret) { const char *name = lGetString(job, JB_script_ptr); if (name == NULL) { /* JB_script_size must not 0 */ ret = object_verify_ulong_null(job, answer_list, JB_script_size); } else { /* JB_script_size must be size of JB_script_ptr */ /* TODO: define a max script size */ if (strlen(name) != lGetUlong(job, JB_script_size)) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_JOB_SCRIPTLENGTHDOESNOTMATCH); ret = false; } } } /* JB_submission_time is overwritten by qmaster */ /* JB_execution_time can be any value */ /* JB_deadline can be any value */ /* JB_owner is overwritten by qmaster */ /* JB_uid is overwritten by qmaster */ /* JB_group is overwritten by qmaster */ /* JB_gid is overwritten by qmaster */ /* JB_account must be a valid string */ if (ret) { const char *name = lGetString(job, JB_account); if (name != NULL) { if(verify_str_key( answer_list, name, MAX_VERIFY_STRING, lNm2Str(JB_account), QSUB_TABLE) != STATUS_OK) { ret = false; } } } /* JB_notify boolean value */ /* JB_type any ulong value */ /* JB_reserve boolean value */ /* * Job priority has a valid range from -1023 to 1024. * As JB_priority is an unsigned long, it is raised by BASE_PRIORITY at * job submission time. * Therefore a valid range is from 1 to 2 * BASE_PRIORITY. */ if (ret) { u_long32 priority = lGetUlong(job, JB_priority); if (priority < 1 || priority > 2 * BASE_PRIORITY) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_PARSE_INVALIDPRIORITYMUSTBEINNEG1023TO1024); ret = false; } } /* JB_jobshare any ulong value */ /* TODO JB_shell_list */ /* JB_verify any ulong value */ /* TODO JB_job_args */ /* JB_checkpoint_attr any ulong */ /* JB_checkpoint_name */ if (ret) { const char *name = lGetString(job, JB_checkpoint_name); if (name != NULL) { if (verify_str_key( answer_list, name, MAX_VERIFY_STRING, lNm2Str(JB_checkpoint_name), KEY_TABLE) != STATUS_OK) { ret = false; } } } /* JB_checkpoint_object */ if (ret) { if (lGetObject(job, JB_checkpoint_object) != NULL) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_INVALIDJOB_REQUEST_S, "checkpoint object"); ret = false; } } /* JB_checkpoint_interval any ulong */ /* JB_restart can be 0, 1 or 2 */ if (ret) { u_long32 value = lGetUlong(job, JB_restart); if (value != 0 && value != 1 && value != 2) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_INVALIDJOB_REQUEST_S, "restart"); ret = false; } } /* TODO: JB_stdout_path_list */ /* TODO: JB_stderr_path_list */ /* TODO: JB_stdin_path_list */ /* JB_merge_stderr boolean value */ /* TODO: JB_hard_resource_list */ /* TODO: JB_soft_resource_list */ /* TODO: JB_hard_queue_list */ /* TODO: JB_soft_queue_list */ /* TODO: JB_mail_options */ /* JB_mail_list any ulong */ /* JB_pe must be a valid string */ if (ret) { const char *name = lGetString(job,JB_pe ); if (name != NULL) { if (verify_str_key( answer_list, name, MAX_VERIFY_STRING, lNm2Str(JB_pe), KEY_TABLE) != STATUS_OK) { ret = false; } } } /* TODO: JB_pe_range */ /* TODO: JB_master_hard_queue */ /* JB_tgt can be any string value */ /* JB_cred can be any string value */ /* TODO: JB_ja_structure */ /* TODO: JB_ja_n_h_ids */ /* TODO: JB_ja_u_h_ids */ /* TODO: JB_ja_s_h_ids */ /* TODO: JB_ja_o_h_ids */ /* TODO: JB_ja_a_h_ids */ /* TODO: JB_ja_z_ids */ /* TODO: JB_ja_template */ /* TODO: JB_ja_tasks */ /* JB_host must be NULL */ if (ret) { if (lGetHost(job, JB_host) != NULL) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_INVALIDJOB_REQUEST_S, "host"); ret = false; } } /* TODO: JB_category */ /* TODO: JB_user_list */ /* TODO: JB_job_identifier_list */ /* JB_verify_suitable_queues must be in range of OPTION_VERIFY_STR */ if (ret) { if (lGetUlong(job, JB_verify_suitable_queues) >= (sizeof(OPTION_VERIFY_STR)/sizeof(char)-1)) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_INVALIDJOB_REQUEST_S, "verify"); ret = false; } } /* JB_soft_wallclock_gm must be 0 */ if (ret) { ret = object_verify_ulong_null(job, answer_list, JB_soft_wallclock_gmt); } /* JB_hard_wallclock_gm must be 0 */ if (ret) { ret = object_verify_ulong_null(job, answer_list, JB_hard_wallclock_gmt); } /* JB_override_tickets must be 0 */ if (ret) { ret = object_verify_ulong_null(job, answer_list, JB_override_tickets); } /* TODO: JB_qs_args */ /* JB_urg must be 0 */ if (ret) { ret = object_verify_double_null(job, answer_list, JB_urg); } /* JB_nurg must be 0 */ if (ret) { ret = object_verify_double_null(job, answer_list, JB_nurg); } /* JB_nppri must be 0 */ if (ret) { ret = object_verify_double_null(job, answer_list, JB_nppri); } /* JB_rrcontr must be 0 */ if (ret) { ret = object_verify_double_null(job, answer_list, JB_rrcontr); } /* JB_dlcontr must be 0 */ if (ret) { ret = object_verify_double_null(job, answer_list, JB_dlcontr); } /* JB_wtcontr must be 0 */ if (ret) { ret = object_verify_double_null(job, answer_list, JB_wtcontr); } /* JB_ja_task_concurrency must be NULL */ if (ret) { u_long32 task_concurrency = lGetUlong(job, JB_ja_task_concurrency); if (task_concurrency > 0 && !job_is_array(job)) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_INVALIDJOB_REQUEST_S, "task concurrency"); ret = false; } } DRETURN(ret); } /****** sge_job/job_get_wallclock_limit() ************************************** * NAME * job_get_wallclock_limit() -- Computes jobs wallclock limit * * SYNOPSIS * bool job_get_wallclock_limit(u_long32 *limit, const lListElem *jep) * * FUNCTION * Compute the jobs wallclock limit depending on requested h_rt, s_rt. * If no limit was requested the maximal ulong32 value is returned * * INPUTS * u_long32 *limit - store for the value * const lListElem *jep - jobs ep * * RESULT * bool - true on success * false if no value was requested * * NOTES * MT-NOTE: job_get_wallclock_limit() is not MT safe * *******************************************************************************/ bool job_get_wallclock_limit(u_long32 *limit, const lListElem *jep) { lListElem *ep; double d_ret = 0, d_tmp; const char *s; bool got_duration = false; char error_str[1024]; DENTER(TOP_LAYER, "job_get_wallclock_limit"); if ((ep=lGetElemStr(lGetList(jep, JB_hard_resource_list), CE_name, SGE_ATTR_H_RT))) { if (parse_ulong_val(&d_tmp, NULL, TYPE_TIM, (s=lGetString(ep, CE_stringval)), error_str, sizeof(error_str)-1)==0) { ERROR((SGE_EVENT, MSG_CPLX_WRONGTYPE_SSS, SGE_ATTR_H_RT, s, error_str)); DRETURN(false); } d_ret = d_tmp; got_duration = true; } if ((ep=lGetElemStr(lGetList(jep, JB_hard_resource_list), CE_name, SGE_ATTR_S_RT))) { if (parse_ulong_val(&d_tmp, NULL, TYPE_TIM, (s=lGetString(ep, CE_stringval)), error_str, sizeof(error_str)-1)==0) { ERROR((SGE_EVENT, MSG_CPLX_WRONGTYPE_SSS, SGE_ATTR_H_RT, s, error_str)); DRETURN(false); } if (got_duration) { d_ret = MIN(d_ret, d_tmp); } else { d_ret = d_tmp; got_duration = true; } } if (got_duration) { if (d_ret > (double)U_LONG32_MAX) { *limit = U_LONG32_MAX; } else { *limit = d_ret; } } else { *limit = U_LONG32_MAX; } DRETURN(got_duration); } /****** sgeobj/job_is_binary() ****************************************** * NAME * job_is_binary() -- Was "job" job submitted with -b y? * * SYNOPSIS * bool job_is_binary(const lListElem *job) * * FUNCTION * This function returns true if "job" is a "binary" job * which was e.g. submitted with qsub -b y * * INPUTS * const lListELem *job - JB_Type element * * RESULT * bool - true or false * * SEE ALSO * sgeobj/job/job_is_array() * sgeobj/job/job_is_binary() * sgeobj/job/job_is_tight_parallel() ******************************************************************************/ bool job_is_binary(const lListElem *job) { return (JOB_TYPE_IS_BINARY(lGetUlong(job, JB_type)) ? true : false); } /* TODO: EB: JSV: add doc */ bool job_set_binary(lListElem *job, bool is_binary) { bool ret = true; u_long32 type = lGetUlong(job, JB_type); if (is_binary) { JOB_TYPE_SET_BINARY(type); } else { JOB_TYPE_CLEAR_BINARY(type); } lSetUlong(job, JB_type, type); return ret; } /* TODO: EB: JSV: add doc */ bool job_is_no_shell(const lListElem *job) { return (JOB_TYPE_IS_NO_SHELL(lGetUlong(job, JB_type)) ? true : false); } /* TODO: EB: JSV: add doc */ bool job_set_no_shell(lListElem *job, bool is_binary) { bool ret = true; u_long32 type = lGetUlong(job, JB_type); if (is_binary) { JOB_TYPE_SET_NO_SHELL(type); } else { JOB_TYPE_CLEAR_NO_SHELL(type); } lSetUlong(job, JB_type, type); return ret; } /* TODO: EB: JSV: add doc */ bool job_set_owner_and_group(lListElem *job, u_long32 uid, u_long32 gid, const char *user, const char *group) { bool ret = true; DENTER(TOP_LAYER, "job_set_owner_and_group"); lSetString(job, JB_owner, user); lSetUlong(job, JB_uid, uid); lSetString(job, JB_group, group); lSetUlong(job, JB_gid, gid); DRETURN(ret); } /* The context comes as a VA_Type list with certain groups of ** elements: A group starts with either: ** (+, ): All following elements are appended to the job's ** current context values, or replaces the current value ** (-, ): The following context values are removed from the ** job's current list of values ** (=, ): The following elements replace the job's current ** context values. ** Any combination of groups is possible. ** To ensure portablity with common sge_gdi, (=, ) is the default ** when no group tag is given at the beginning of the incoming list */ /* jbctx - VA_Type; job - JB_Type */ void set_context(lList *jbctx, lListElem *job) { lList* newjbctx = NULL; lListElem* jbctxep; lListElem* temp; char mode = '+'; newjbctx = lGetList(job, JB_context); /* if the incoming list is empty, then simply clear the context */ if (!jbctx || !lGetNumberOfElem(jbctx)) { lSetList(job, JB_context, NULL); newjbctx = NULL; } else { /* if first element contains no tag => assume (=, ) */ switch(*lGetString(lFirst(jbctx), VA_variable)) { case '+': case '-': case '=': break; default: lSetList(job, JB_context, NULL); newjbctx = NULL; break; } } for_each(jbctxep, jbctx) { switch(*(lGetString(jbctxep, VA_variable))) { case '+': mode = '+'; break; case '-': mode = '-'; break; case '=': lSetList(job, JB_context, NULL); newjbctx = NULL; mode = '+'; break; default: switch(mode) { case '+': if (!newjbctx) lSetList(job, JB_context, newjbctx = lCreateList("context_list", VA_Type)); if ((temp = lGetElemStr(newjbctx, VA_variable, lGetString(jbctxep, VA_variable)))) lSetString(temp, VA_value, lGetString(jbctxep, VA_value)); else lAppendElem(newjbctx, lCopyElem(jbctxep)); break; case '-': lDelSubStr(job, VA_variable, lGetString(jbctxep, VA_variable), JB_context); /* WARNING: newjbctx is not valid when complete list was deleted */ break; } break; } } } bool job_get_ckpt_attr(int op, dstring *string) { bool success = true; DENTER(TOP_LAYER, "job_get_ckpt_attr"); if (VALID(CHECKPOINT_AT_MINIMUM_INTERVAL, op)) { sge_dstring_append_char(string, CHECKPOINT_AT_MINIMUM_INTERVAL_SYM); } if (VALID(CHECKPOINT_AT_SHUTDOWN, op)) { sge_dstring_append_char(string, CHECKPOINT_AT_SHUTDOWN_SYM); } if (VALID(CHECKPOINT_SUSPEND, op)) { sge_dstring_append_char(string, CHECKPOINT_SUSPEND_SYM); } if (VALID(NO_CHECKPOINT, op)) { sge_dstring_append_char(string, NO_CHECKPOINT_SYM); } DRETURN(success); } bool job_get_verify_attr(u_long32 op, dstring *string) { bool success = true; DENTER(TOP_LAYER, "job_get_verify_attr"); if (ERROR_VERIFY == op) { sge_dstring_append_char(string, 'e'); } else if (WARNING_VERIFY == op) { sge_dstring_append_char(string, 'w'); } else if (JUST_VERIFY == op) { sge_dstring_append_char(string, 'v'); } else if (POKE_VERIFY == op) { sge_dstring_append_char(string, 'p'); } else { sge_dstring_append_char(string, 'n'); } DRETURN(success); } bool job_parse_validation_level(int *level, const char *input, int prog_number, lList **answer_list) { bool ret = true; DENTER(TOP_LAYER, "job_parse_validation_level"); if (strcmp("e", input) == 0) { if (prog_number == QRSUB) { *level = AR_ERROR_VERIFY; } else { *level = ERROR_VERIFY; } } else if (strcmp("w", input) == 0) { if (prog_number == QRSUB) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_PARSE_INVALIDOPTIONARGUMENTWX_S, input); ret = false; } else { *level = WARNING_VERIFY; } } else if (strcmp("n", input) == 0) { if (prog_number == QRSUB) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_PARSE_INVALIDOPTIONARGUMENTWX_S, input); ret = false; } else { *level = SKIP_VERIFY; } } else if (strcmp("v", input) == 0) { if (prog_number == QRSUB) { *level = AR_JUST_VERIFY; } else { *level = JUST_VERIFY; } } else if (strcmp("p", input) == 0) { if (prog_number == QRSUB) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_PARSE_INVALIDOPTIONARGUMENTWX_S, input); ret = false; } else { *level = POKE_VERIFY; } } else { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_PARSE_INVALIDOPTIONARGUMENTWX_S, input); ret = false; } DRETURN(ret); } /****** sgeobj/job_is_requesting_consumable() ****************************************** * NAME * job_is_requesting_consumable() -- Is job requesting resources of type * CONSUMABLE_JOB? * * SYNOPSIS * bool job_is_requesting_consumable(lListElem *jep, const char *resoure_name) * * FUNCTION * This function returns true if "job" is requesting a resource with type * CONSUMABLE_JOB. * * INPUTS * lListELem *jep - JB_Type element * const char *resource_name - Name of resource * * RESULT * bool - true or false * * SEE ALSO ******************************************************************************/ bool job_is_requesting_consumable(lListElem *jep, const char *resource_name) { lList *request_list; lListElem *cep = NULL; u_long32 consumable; request_list = lGetList(jep, JB_hard_resource_list); if (request_list != NULL) { cep = centry_list_locate(request_list, resource_name); if (cep != NULL) { consumable = lGetUlong(cep, CE_consumable); if (consumable == CONSUMABLE_JOB) { return true; } } } return false; } bool job_init_binding_elem(lListElem *jep) { bool ret = true; lList *binding_list = lCreateList("", BN_Type); lListElem *binding_elem = lCreateElem(BN_Type); if (binding_elem != NULL && binding_list != NULL) { lAppendElem(binding_list, binding_elem); lSetList(jep, JB_binding, binding_list); lSetString(binding_elem, BN_strategy, "no_job_binding"); lSetUlong(binding_elem, BN_type, BINDING_TYPE_NONE); lSetUlong(binding_elem, BN_parameter_n, 0); lSetUlong(binding_elem, BN_parameter_socket_offset, 0); lSetUlong(binding_elem, BN_parameter_core_offset, 0); lSetUlong(binding_elem, BN_parameter_striding_step_size, 0); lSetString(binding_elem, BN_parameter_explicit, "no_explicit_binding"); } else { ret = false; } return ret; }