/*___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 #include "rmon/sgermon.h" #include "uti/sge_string.h" #include "uti/sge_log.h" #include "cull/cull_list.h" #include "sge_range.h" #include "sge_ja_task.h" #include "sge_pe_task.h" #include "sge_mesobj.h" #include "sge_job.h" #include "sge_id.h" #include "sge_str.h" #include "sge_object.h" #include "sge_answer.h" #include "sge_pe.h" #include "sge_qinstance.h" #include "sge_utility.h" #include "sge_usage.h" #include "msg_common.h" #include "msg_sgeobjlib.h" /****** sgeobj/ja_task/ja_task_search_pe_task()********************************* * NAME * ja_task_search_pe_task() -- Find a certain PE Task * * SYNOPSIS * lListElem* ja_task_search_pe_task(const lListElem *ja_task, * const char **pe_task_id) * * FUNCTION * Find a certain PE Task with "pe_task_id" in "ja_task" * * INPUTS * const lListElem *ja_task - JAT_Type element * const char *pe_task_id - PE task id string (e.g. "1.speedy") * * RESULT * lListElem* - PET_Type *******************************************************************************/ lListElem *ja_task_search_pe_task(const lListElem *ja_task, const char *pe_task_id) { if(ja_task != NULL) { lList *pe_tasks = lGetList(ja_task, JAT_task_list); if(pe_tasks != NULL) { return lGetElemStr(pe_tasks, PET_id, pe_task_id); } } return NULL; } /****** sgeobj/ja_task/ja_task_list_print_to_string() ************************** * NAME * ja_task_list_print_to_string() -- print task id ranges into string * * SYNOPSIS * void ja_task_list_print_to_string(const lList *ja_task_list, * dstring *range_string) * * FUNCTION * The ids of all tasks contained in 'ja_task_list' will be printed * into 'range_string'. * * INPUTS * const lList *ja_task_list - JAT_Type list * dstring *range_string - dynamic string ******************************************************************************/ void ja_task_list_print_to_string(const lList *ja_task_list, dstring *range_string) { lListElem *ja_task = NULL; /* JAT_Type */ lList *range_list = NULL; /* RN_Type */ DENTER(TOP_LAYER, "ja_task_list_print_to_string"); for_each(ja_task, ja_task_list) { u_long32 tid = lGetUlong(ja_task, JAT_task_number); range_list_insert_id(&range_list, NULL, tid); } range_list_sort_uniq_compress(range_list, NULL, true); range_list_print_to_string(range_list, range_string, false, false, false); lFreeList(&range_list); DRETURN_VOID; } /****** sgeobj/ja_task/ja_task_list_split_group() ****************************** * NAME * ja_task_list_split_group() -- Splits a list into two parts * * SYNOPSIS * lList* ja_task_list_split_group(lList **ja_task_list) * * FUNCTION * All tasks which have the same state (JAT_status, JAT_state) like * the first element of 'ja_task_list' will be removed from i * 'ja_task_list' and returned by this function. * * INPUTS * lList **ja_task_list - JAT_Type list * * RESULT * lList* - JAT_Type list (elements with equivalent state) * * SEE ALSO * sgeobj/range/RN_Type ******************************************************************************/ lList* ja_task_list_split_group(lList **ja_task_list) { lList *ret_list = NULL; if (ja_task_list && *ja_task_list) { lListElem *first_task = lFirst(*ja_task_list); if (first_task) { u_long32 status = lGetUlong(first_task, JAT_status); u_long32 state = lGetUlong(first_task, JAT_state); u_long32 hold = lGetUlong(first_task, JAT_hold); const lDescr *descr = lGetElemDescr(first_task); lCondition *where = NULL; where = lWhere("%T(%I != %u || %I != %u || %I != %u)", descr, JAT_status, status, JAT_state, state, JAT_hold, hold); lSplit(ja_task_list, &ret_list, NULL, where); lFreeWhere(&where); } } return ret_list; } /****** sgeobj/ja_task/ja_task_add_finished_pe_task() ************************** * NAME * ja_task_add_finished_pe_task() -- remember finished parallel task * * SYNOPSIS * bool * ja_task_add_finished_pe_task(lListElem *ja_task, * const char *pe_task_id) * * FUNCTION * To avoid duplicate handling of finished parallel tasks (which * could be triggered by sge_execd sending task end reports multiple * times until it receives an ack from qmaster), the ja_task object * (JAT_Type) contains a list of finished parallel tasks. * * ja_task_add_finished_pe_task tries to add a new parallel task to * this list. * * If an entry with the given pe_task_id already exists, the function * returns false, else true. * * INPUTS * lListElem *ja_task - the ja_task to check/modify * const char *pe_task_id - the pe_task_id to check/insert * * RESULT * bool - error state * true - if the pe_task_id did not yet exist and could be inserted, * false - if the pe_task_id already existed. * * SEE ALSO * sgeobj/ja_task/ja_task_clear_finished_pe_tasks() *******************************************************************************/ bool ja_task_add_finished_pe_task(lListElem *ja_task, const char *pe_task_id) { lListElem *pe_task; DENTER(TOP_LAYER, "ja_task_add_finished_pe_task"); pe_task = lGetSubStr(ja_task, FPET_id, pe_task_id, JAT_finished_task_list); if (pe_task != NULL) { INFO((SGE_EVENT, "already handled exit of pe task "SFQ" in ja_task " sge_U32CFormat"\n", pe_task_id, sge_u32c(lGetUlong(ja_task, JAT_task_number)))); DRETURN(false); } pe_task = lAddSubStr(ja_task, FPET_id, pe_task_id, JAT_finished_task_list, FPET_Type); DRETURN(true); } /****** sgeobj/ja_task/ja_task_clear_finished_pe_tasks() *********************** * NAME * ja_task_clear_finished_pe_tasks() -- clear finished task list * * SYNOPSIS * bool * ja_task_clear_finished_pe_tasks(lListElem *ja_task) * * FUNCTION * A ja_task contains a list of all finished parallel tasks (see also * sgeobj/ja_task/ja_task_add_finished_pe_task()). * * In certain circumstances (e.g. if a ja_task is rescheduled), it is * necessary to clear this list. * * ja_task_clear_finished_pe_tasks removes the complete sublist including * the contained task ids. * * INPUTS * lListElem *ja_task - the ja_task to modify * * RESULT * bool - true, if the list could be cleared, * false, if no list of finished pe_tasks existed. * * SEE ALSO * sgeobj/ja_task/ja_task_add_finished_pe_task() *******************************************************************************/ bool ja_task_clear_finished_pe_tasks(lListElem *ja_task) { lList *pe_task_list; DENTER(TOP_LAYER, "ja_task_clear_finished_pe_tasks"); /* get list of finished pe tasks */ pe_task_list = lGetList(ja_task, JAT_finished_task_list); if (pe_task_list == NULL) { DPRINTF(("no finished pe task list to clear in ja_task "sge_U32CFormat"\n", lGetUlong(ja_task, JAT_task_number))); DRETURN(false); } /* if we have such a list, delete it (lSetList will free the list) */ lSetList(ja_task, JAT_finished_task_list, NULL); DPRINTF(("cleared finished pe task list in ja_task "sge_U32CFormat"\n", lGetUlong(ja_task, JAT_task_number))); DRETURN(true); } /****** parse/sge_parse_jobtasks() ********************************************* * NAME * sge_parse_jobtasks() -- parse array task ranges * * SYNOPSIS * int sge_parse_jobtasks(lList **ipp, lListElem **idp, const char * *str_jobtask, lList **alpp, bool include_names, lList *arrayDefList) * * FUNCTION * parses a job ids with or without task ranges following this pattern: * Digit = '0' | '1' | ... | '9' . * JobId = Digit { Digit } . * TaskIdRange = TaskId [ '-' TaskId [ ':' Digit ] ] . * JobTasks = JobId [ '.' TaskIdRange ] . * * in case of a job name, the task range has to be specified extra. This * will be colleced in an extra list and handed in as the arrayDefList * * INPUTS * lList **ipp - ID_Type List, target list * lListElem **idp - New ID_Type-Elem parsed from str_jobtask * const char *str_jobtask - job id with task range or job name * lList **alpp - answer list * bool include_names - true: job names are allowed * lList *arrayDefList - in case of job names, a list of array taskes * * RESULT * int - -1 no valid JobTask-Identifier * 0 everything went fine * * * NOTES * MT-NOTE: sge_parse_jobtasks() is MT safe * *******************************************************************************/ int sge_parse_jobtasks(lList **ipp, lListElem **idp, const char *str_jobtask, lList **alpp, bool include_names, lList *arrayDefList) { char *token; char *job_str; lList *task_id_range_list = NULL; int ret = 1; DENTER(TOP_LAYER, "sge_parse_jobtasks"); job_str = strdup(str_jobtask); /* An empty job id string is a bad job id string! */ if (strcmp (job_str, "") == 0) { ret = -1; } /* ** dup the input string for tokenizing */ else if(isdigit(job_str[0])) { const double epsilon = 1.0E-12; char *end_ptr = NULL; double dbl_value; u_long32 ulng_value; if ((token = strchr(job_str, '.')) != NULL){ token[0] = '\0'; token++; if (!range_list_parse_from_string(&task_id_range_list, alpp, token, false, true, INF_NOT_ALLOWED) || !task_id_range_list) { ret = -1; } } dbl_value = strtod(job_str, &end_ptr); ulng_value = dbl_value; if ((dbl_value < 1) || (dbl_value - ulng_value > epsilon) || (end_ptr == NULL) || (end_ptr[0] != '\0')) { ret = -1; } } if (arrayDefList != NULL) { if (task_id_range_list == NULL) { task_id_range_list = lCopyList(lGetListName(arrayDefList), arrayDefList); } else { lList *copy = lCopyList("", arrayDefList); lAddList(task_id_range_list, ©); } } if (ret == 1) { if (!include_names && !isdigit(job_str[0]) && (strcmp(job_str, "\"*\"") != 0)) { ret = -1; } else { *idp = lAddElemStr(ipp, ID_str, job_str, ID_Type); if (*idp) { range_list_sort_uniq_compress(task_id_range_list, alpp, true); lSetList(*idp, ID_ja_structure, task_id_range_list); } } } /* ** free the dupped string */ FREE(job_str); DRETURN(ret); } /****** sgeobj/ja_task/ja_task_message_add() ********************************** * NAME * ja_task_message_add() -- add a message to the message list of a task * * SYNOPSIS * bool * ja_task_message_add(lListElem *this_elem, u_long32 type, * const char *message) * * FUNCTION * Adds a message in the "JAT_message_list"-message list of "this_elem" * "type" will be the message type. "message" is the text string stored * int the new element of the sublist. * * INPUTS * lListElem *this_elem - JAT_Type element * u_long32 type - message type id * const char *message - message * * RESULT * bool - error state * true - success * false - error * * NOTES * MT-NOTE: ja_task_message_add() is MT safe * * SEE ALSO * sgeobj/ja_task/ja_task_message_trash_all_of_type_X() *******************************************************************************/ bool ja_task_message_add(lListElem *this_elem, u_long32 type, const char *message) { bool ret = true; DENTER(TOP_LAYER, "ja_task_message_add"); ret = object_message_add(this_elem, JAT_message_list, type, message); DRETURN(ret); } /****** sgeobj/ja_task/ja_task_message_trash_all_of_type_X() ****************** * NAME * ja_task_message_trash_all_of_type_X() -- Trash messages of certain type * * SYNOPSIS * bool * ja_task_message_trash_all_of_type_X(lListElem *this_elem, * u_long32 type) * * FUNCTION * Trash all messages from the sublist of JAT_message_list which are of * the given "type". * * * INPUTS * lListElem *this_elem - JAT_Type element * u_long32 type - type id * * RESULT * bool - error state * true - success * false - error * * NOTES * MT-NOTE: ja_task_message_trash_all_of_type_X() is MT safe *******************************************************************************/ bool ja_task_message_trash_all_of_type_X(lListElem *this_elem, u_long32 type) { bool ret = true; DENTER(TOP_LAYER, "ja_task_message_trash_all_of_type_X"); ret = object_message_trash_all_of_type_X(this_elem, JAT_message_list, type); DRETURN(ret); } /****** sge_ja_task/ja_task_verify() ******************************************* * NAME * ja_task_verify() -- verify a ja_task object * * SYNOPSIS * bool * ja_task_verify(const lListElem *ja_task, lList **answer_list) * * FUNCTION * Verify correctness of a ja_task object. * * INPUTS * const lListElem *ja_task - the ja_task to verify * lList **answer_list - answer list to pass back error messages * * RESULT * bool - true: everything ok, else false * * NOTES * MT-NOTE: ja_task_verify() is MT safe * * SEE ALSO * sge_ja_task/ja_task_verify_execd_job() *******************************************************************************/ bool ja_task_verify(const lListElem *ja_task, lList **answer_list) { bool ret = true; DENTER(TOP_LAYER, "ja_task_verify"); ret = object_verify_ulong_not_null(ja_task, answer_list, JAT_task_number); /* * TODO: JAT_status, * TODO: JAT_start_time, * TODO: JAT_end_time, * TODO: JAT_hold, * TODO: JAT_granted_pe, * TODO: JAT_job_restarted, * TODO: JAT_master_queue, * TODO: JAT_state, * TODO: JAT_pvm_ckpt_pid, * TODO: JAT_pending_signal, * TODO: JAT_pending_signal_delivery_time, * TODO: JAT_pid, * TODO: JAT_osjobid, * TODO: JAT_usage_list, * TODO: JAT_scaled_usage_list, * TODO: JAT_reported_usage_list, * TODO: JAT_fshare, * TODO: JAT_tix, * TODO: JAT_oticket, * TODO: JAT_fticket, * TODO: JAT_sticket, * TODO: JAT_share, * TODO: JAT_suitable, * TODO: JAT_task_list, * TODO: JAT_finished_task_list, * TODO: JAT_previous_usage_list, * TODO: JAT_pe_object, * TODO: JAT_next_pe_task_id, * TODO: JAT_stop_initiate_time, * TODO: JAT_prio, * TODO: JAT_ntix, * TODO: JAT_message_list */ DRETURN(ret); } /****** sge_ja_task/ja_task_verify_execd_job() ********************************* * NAME * ja_task_verify_execd_job() -- verify a ja_task object for execd * * SYNOPSIS * bool * ja_task_verify_execd_job(const lListElem *ja_task, lList **answer_list) * * FUNCTION * Verify a ja_task object that has been sent to execd. * * INPUTS * const lListElem *ja_task - the ja_task object to verify * lList **answer_list - answer list to pass back error messages * * RESULT * bool - true: everything ok, else false * * NOTES * MT-NOTE: ja_task_verify_execd_job() is MT safe * * SEE ALSO * sge_ja_task/ja_task_verify() *******************************************************************************/ bool ja_task_verify_execd_job(const lListElem *ja_task, lList **answer_list) { bool ret = true; DENTER(TOP_LAYER, "ja_task_verify_execd_job"); ret = ja_task_verify(ja_task, answer_list); if (ret) { ret = ja_task_verify_granted_destin_identifier_list(lGetList(ja_task, JAT_granted_destin_identifier_list), answer_list); } DRETURN(ret); } /****** sge_ja_task/ja_task_verify_granted_destin_identifier_list() ************ * NAME * ja_task_verify_granted_destin_identifier_list() -- verify granted destination identifier list * * SYNOPSIS * bool * ja_task_verify_granted_destin_identifier_list(const lList *gdil, * lList **answer_list) * * FUNCTION * Verify correctness of a granted destination identifier list being part * of a scheduled ja_task. * * INPUTS * const lList *gdil - the list to verify * lList **answer_list - answer list to pass back error messages * * RESULT * bool - true: everything ok, else false * * NOTES * MT-NOTE: ja_task_verify_granted_destin_identifier_list() is MT safe * * SEE ALSO * sge_ja_task/ja_task_verify_granted_destin_identifier() *******************************************************************************/ bool ja_task_verify_granted_destin_identifier_list(const lList *gdil, lList **answer_list) { bool ret = true; DENTER(TOP_LAYER, "ja_task_verify_granted_destin_identifier_list"); if (gdil == NULL) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_INVALID_GDIL); ret = false; } if (ret) { const lListElem *ep; for_each (ep, gdil) { ret = ja_task_verify_granted_destin_identifier(ep, answer_list); if (!ret) { break; } } } DRETURN(ret); } /****** sge_ja_task/ja_task_verify_granted_destin_identifier() ***************** * NAME * ja_task_verify_granted_destin_identifier() -- verify a granted destination identifier * * SYNOPSIS * bool * ja_task_verify_granted_destin_identifier(const lListElem *ep, * lList **answer_list) * * FUNCTION * Verify a single element of a granted destination identifier list * (a granted queue with a certain number of slots). * * INPUTS * const lListElem *ep - the element to verify * lList **answer_list - answer list to pass back error messages * * RESULT * bool - true: everything ok, else false * * NOTES * MT-NOTE: ja_task_verify_granted_destin_identifier() is MT safe * * SEE ALSO * sge_ja_task/ja_task_verify_granted_destin_identifier_list() *******************************************************************************/ bool ja_task_verify_granted_destin_identifier(const lListElem *ep, lList **answer_list) { bool ret = true; DENTER(TOP_LAYER, "ja_task_verify_granted_destin_identifier"); if (ep == NULL) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_NULLELEMENTPASSEDTO_S, SGE_FUNC); ret = false; } if (ret) { ret = qinstance_verify_full_name(answer_list, lGetString(ep, JG_qname)); } if (ret) { ret = verify_host_name(answer_list, lGetHost(ep, JG_qhostname)); } if (ret) { ret = object_verify_ulong_not_null(ep, answer_list, JG_slots); } if (ret) { const lListElem *queue = lGetObject(ep, JG_queue); if (queue != NULL) { ret = qinstance_verify(queue, answer_list); } } DRETURN(ret); } /****** sge_ja_task/ja_task_is_tightly_integrated() **************************** * NAME * ja_task_is_tightly_integrated() -- is this a tightly integrated job? * * SYNOPSIS * bool ja_task_is_tightly_integrated(const lListElem *ja_task) * * FUNCTION * Figures out, if a running ja task belongs to a tightly integrated * parallel job. * * INPUTS * const lListElem *ja_task - the ja task to test * * RESULT * bool - true if it is a tightly integrated parallel job, else false * * NOTES * MT-NOTE: ja_task_is_tightly_integrated() is MT safe, the caller must * hold a read lock on the SGE_TYPE_PE list. *******************************************************************************/ bool ja_task_is_tightly_integrated(const lListElem *ja_task) { bool ret = false; object_description *object_base = object_type_get_object_description(); if (ja_task != NULL) { const char *pe_name = lGetString(ja_task, JAT_granted_pe); if (pe_name != NULL) { const lListElem *pe = pe_list_locate(*object_base[SGE_TYPE_PE].list, pe_name); if (pe != NULL) { if (lGetBool(pe, PE_control_slaves)) { ret = true; } } } } return ret; }