summaryrefslogtreecommitdiff
path: root/src/argos_thread.c
blob: 59fc4dcd9c374b913ad802b8a7a6ff963a72da51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "common.h"
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>

static pthread_mutex_t aw_mutex;
static pthread_cond_t aw_cond;

static unsigned int thread_timeout;
static bool thread_watchdog_running;

static void *aw_thread_main(void * data)
{
	int ret;
	struct timespec ts;

	while (1) {
		pthread_mutex_lock(&aw_mutex);

		memset(&ts, 0, sizeof(ts));
		clock_gettime(CLOCK_MONOTONIC, &ts);
		_D("current time %lld.%.9ld", (long long)ts.tv_sec, ts.tv_nsec);
		ts.tv_sec += thread_timeout;
		_D("wait time %lld.%.9ld", (long long)ts.tv_sec, ts.tv_nsec);
		ret = pthread_cond_timedwait(&aw_cond, &aw_mutex, &ts);
		_D("wakeup : %d", ret);
		if (ret == ETIMEDOUT && thread_watchdog_running) {
			aw_notify_watchdog();
			break;
		}

		pthread_mutex_unlock(&aw_mutex);
	}
	return NULL;
}

int aw_register_thread(unsigned int timeout)
{
	int ret = 0;
	pthread_t pth = 0;
	pthread_condattr_t cattr;

	if (timeout == 0)
		return -EINVAL;

	pthread_mutex_init(&aw_mutex, NULL);
	pthread_condattr_init(&cattr);
	pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
	pthread_cond_init(&aw_cond, &cattr);
	thread_timeout = timeout;
	thread_watchdog_running = true;

	_D("create watchdog thread with %d", thread_timeout);
	ret = pthread_create(&pth, NULL, &aw_thread_main, (void *)NULL);
	if (ret)
		return ret;

	pthread_detach(pth);
	return ret;
}

int aw_control_thread(aw_op_e op, void *data)
{
	int ret = 0;
	unsigned int* timeout;

	pthread_mutex_lock(&aw_mutex);
	switch(op){
	case AW_OP_DISABLE:
		thread_watchdog_running = false;
		break;

	case AW_OP_ENABLE:
		thread_watchdog_running = true;
		break;

	case AW_OP_CHANGE_TIMEOUT:
		timeout = (unsigned int*)(data);
		if(timeout == NULL){
			ret = -1;
			break;
		}
		thread_timeout = *timeout;
		break;
	default:
		ret = -1;
		break;
	}
	pthread_mutex_unlock(&aw_mutex);

	return ret;
}

int aw_notify_thread(void)
{
	int ret;

	ret = pthread_mutex_trylock(&aw_mutex);
	if (ret == 0) {
		_D("send notify");
		pthread_cond_signal(&aw_cond);
		pthread_mutex_unlock(&aw_mutex);
	}

	return ret;
}