?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Operating System : Date Time Management' ??
MODULE osm$date_time_management;

{ PURPOSE:
{   This module contains procedures needed to manage date and time in osf$system_core_113 and osf$boot_job.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$mainframe_pageable
*copyc ost$os_defaults
?? POP ??
*IF NOT $true(osv$unix)
*copyc dsp$read_date_time_information
*copyc dsp$read_mrt_entry
*copyc osp$clear_mainframe_sig_lock
*copyc osp$set_mainframe_sig_lock
*copyc pmp$get_time
*copyc pmp$verify_compact_date
*copyc pmp$verify_compact_time
?? EJECT ??
*copyc dsv$mainframe_type
*copyc osv$base_system_time
*copyc osv$date_time_update
*IFEND
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
  VAR

    { The os name must not be part of the os defaults record because it is accessed by the linker.

    osv$os_defaults: [XDCL, #GATE, oss$mainframe_pageable] ost$os_defaults :=
          [[0], TRUE, [0, 0, FALSE], [osc$iso_date, 'Y4-M2-D2'], [osc$hms_time, 'HMS'],
           [FALSE, 0, [0, 0]]],

    osv$os_defaults_os_name: [XDCL, #GATE, oss$mainframe_pageable] ost$os_defaults_os_name :=
*IF NOT $true(osv$unix)
          'NOS/VE R1  12205 /3DX     ';
*ELSE
          '                          ';
*IFEND

?? OLDTITLE ??
*IF NOT $true(osv$unix)
?? NEWTITLE := 'osp$change_base_system_time', EJECT ??

{ PURPOSE:
{   This procedure will update the base system time.  It does NOT update the hardware clock (chip).

  PROCEDURE [XDCL, #GATE] osp$change_base_system_time
    (    free_running_clock: ost$free_running_clock;
         date_time: ost$date_time;
     VAR status: ost$status);

    VAR
      base_system_time: ost$base_system_time,
      i_date_time: ost$date_time,
      time: ost$time;

    i_date_time := date_time;
    base_system_time.second := i_date_time.second;
    base_system_time.minute := i_date_time.minute;
    base_system_time.hour := i_date_time.hour;
    base_system_time.day := i_date_time.day;
    base_system_time.month := i_date_time.month;

{ This code allows NOS/VE to exist until 2079, if by chance it lasts longer,
{ then this code would have to be changed.

    IF date_time.year < 80 THEN
      i_date_time.year := i_date_time.year + 100;
    IFEND;

    pmp$verify_compact_date (i_date_time, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pmp$verify_compact_time (i_date_time, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    base_system_time.year := i_date_time.year + 1900;
    base_system_time.corresponding_microsecond_clock := free_running_clock;

    { There is a small window here for errors.  If the following assignment is not completed before
    { another task or processor accesses OSV$BASE_SYSTEM_TIME from PMM$GET_COMPACT_DATE_TIME, unpredictable
    { results will occur.  Locking this variable is too expensive for the number of times its referenced.

    osv$base_system_time := base_system_time;

    { Clear the date/time update flag which is set by 170 or the Cyber 2000 Service Processor changing time.

    osv$date_time_update := FALSE;

    pmp$get_time (osc$hms_time, time, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    osp$set_mainframe_sig_lock (osv$os_defaults.lock);
    osv$os_defaults.defaults_changed := TRUE;
    osp$clear_mainframe_sig_lock (osv$os_defaults.lock);

  PROCEND osp$change_base_system_time;
?? OLDTITLE ??
?? NEWTITLE := 'osp$initialize_date_time', EJECT ??

{ PURPOSE
{   This procedure initializes the date/time from the MRT values.  This is done at deadstart time and
{   whenever NOS or the Service Processor changes the time.

  PROCEDURE [XDCL, #GATE] osp$initialize_date_time
    (VAR status: ost$status);

    VAR
      date_time: ost$date_time,
      date_time_information: dst$date_time_information,
      free_running_clock: integer,
      mrt_entry: dst$mrt_entry;

    status.normal := TRUE;
    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      dsp$read_date_time_information (date_time_information, status);
      IF NOT status.normal THEN
         RETURN;
      IFEND;
      date_time := date_time_information.bst_wcc;
      free_running_clock := date_time_information.bst_frc;
    ELSE
      dsp$read_mrt_entry (dsc$mrt_id_clock_data, 0, mrt_entry, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      date_time.millisecond := 0;
      date_time.second := mrt_entry.clock_data.seconds.units + mrt_entry.clock_data.seconds.tens * 10;
      date_time.minute := mrt_entry.clock_data.minutes.units + mrt_entry.clock_data.minutes.tens * 10;
      date_time.hour := mrt_entry.clock_data.hours.units + mrt_entry.clock_data.hours.tens * 10;
      date_time.day := mrt_entry.clock_data.days.units + mrt_entry.clock_data.days.tens * 10;
      date_time.month := mrt_entry.clock_data.months.units + mrt_entry.clock_data.months.tens * 10;
      date_time.year := mrt_entry.clock_data.years.units + mrt_entry.clock_data.years.tens * 10;
      free_running_clock := mrt_entry.clock_data.frc_bits_52_63.frc_bits +
            mrt_entry.clock_data.frc_bits_40_51.frc_bits * 1000(16) +
            mrt_entry.clock_data.frc_bits_28_39.frc_bits * 1000000(16) +
            mrt_entry.clock_data.frc_bits_16_27.frc_bits * 1000000000(16) +
            mrt_entry.clock_data.frc_bits_4_15.frc_bits * 1000000000000(16);
    IFEND;

    osp$change_base_system_time (free_running_clock, date_time, status);

    osp$set_mainframe_sig_lock (osv$os_defaults.lock);
    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      osv$os_defaults.system_date_format := date_time_information.default_date;
      osv$os_defaults.system_time_format := date_time_information.default_time;
    IFEND;
    osv$os_defaults.defaults_changed := TRUE;
    osv$os_defaults.time_data.wait_count := 0;
    osv$os_defaults.time_data.wait_to_change := FALSE;
    osp$clear_mainframe_sig_lock (osv$os_defaults.lock);

  PROCEND osp$initialize_date_time;
?? OLDTITLE ??
*IFEND
MODEND osm$date_time_management;
