* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "ascend_hal.h"
#include "securec.h"
#include "ascend_hal_error.h"
#include "dms_user_common.h"
#include "dms_time_zone.h"
#ifdef STATIC_SKIP
#define STATIC
#else
#define STATIC static
#endif
STATIC pthread_mutex_t g_dms_time_sync_mutex = PTHREAD_MUTEX_INITIALIZER;
STATIC pthread_t g_dms_time_sync_thread;
STATIC u8 g_dms_time_sync_work = 0;
#define DMS_TIME_THREAD_STACK_SIZE (128 * 1024)
STATIC drvError_t dms_set_time_sync(void *data, struct dms_time_sync *interval_time)
{
(void)data;
struct dms_ioctl_arg ioarg = {0};
int ret;
ioarg.main_cmd = DMS_MAIN_CMD_BASIC;
ioarg.sub_cmd = DMS_SET_TIME_ZONE_SYNC;
ioarg.filter_len = 0;
ioarg.input = (void *)interval_time;
ioarg.input_len = sizeof(struct dms_time_sync);
ioarg.output = NULL;
ioarg.output_len = 0;
ret = errno_to_user_errno(DmsIoctl(DMS_IOCTL_CMD, &ioarg));
if (ret != 0) {
ret = (ret == DRV_ERROR_PARA_ERROR) ? DRV_ERROR_INNER_ERR : ret;
DMS_EX_NOTSUPPORT_ERR(ret, "Set time sync failed. (ret=%d)\n", ret);
return ret;
}
DMS_DEBUG("Set time sync success.\n");
return DRV_ERROR_NONE;
}
STATIC void dms_get_iterval_seconds(struct dms_time_sync *interval_time)
{
long interval;
time_t local;
time_t utc;
struct tm tmp_ptr;
(void)time(&local);
(void)gmtime_r(&local, &tmp_ptr);
utc = mktime(&tmp_ptr);
interval = local - utc;
interval_time->interval_seconds = interval;
DMS_DEBUG("Interval seconds between local seconds and utc. (interval=%lds)\n", interval);
}
STATIC void *dms_time_sync_serve_thread_device(void *data)
{
struct dms_time_sync interval_time = {0};
int ret;
DMS_INFO("device manager time zone sync serve start.\n");
(void)prctl(PR_SET_NAME, "dms_time_sync");
while (g_dms_time_sync_work != 0) {
(void)sleep(5);
dms_get_iterval_seconds(&interval_time);
ret = dms_set_time_sync(data, &interval_time);
if (ret != 0) {
DMS_EX_NOTSUPPORT_ERR(ret, "ioctl failed, ret(%d), stop time sync thread.\n", ret);
break;
}
}
DMS_INFO("device manager time zone sync serve stop.\n");
return NULL;
}
drvError_t dmsStartTimeSyncServeDevice(void)
{
pthread_attr_t attr = {{0}};
int ret;
(void)pthread_mutex_lock(&g_dms_time_sync_mutex);
if (g_dms_time_sync_work != 0) {
(void)pthread_mutex_unlock(&g_dms_time_sync_mutex);
DMS_INFO("time sync thread has already started.\n");
return DRV_ERROR_NONE;
}
g_dms_time_sync_work = 1;
(void)pthread_attr_init(&attr);
(void)pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
(void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
(void)pthread_attr_setstacksize(&attr, DMS_TIME_THREAD_STACK_SIZE);
ret = pthread_create(&g_dms_time_sync_thread, &attr, dms_time_sync_serve_thread_device, NULL);
if (ret != 0) {
DMS_ERR("pthread_create fail, unable to create timezone sync thread.\n");
g_dms_time_sync_work = 0;
(void)pthread_attr_destroy(&attr);
(void)pthread_mutex_unlock(&g_dms_time_sync_mutex);
return DRV_ERROR_SOCKET_CREATE;
}
(void)pthread_attr_destroy(&attr);
(void)pthread_mutex_unlock(&g_dms_time_sync_mutex);
return DRV_ERROR_NONE;
}