-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdynamic_c.h
254 lines (182 loc) · 6.82 KB
/
dynamic_c.h
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/**
* @file Dynamic_c.h is a library that provides tools for a dynamic update of C programs.
*/
#ifndef UPDATE_DYNAMIC_C
#define UPDATE_DYNAMIC_C
#include <signal.h>
#include <stdlib.h>
#include <rpc/xdr.h>
#include <string.h>
#include <unistd.h>
#include "structures.h"
#include <time.h>
char PROGRAM_NAME[100];
update_variables *up_var;
char ser_up_var[100];
char ser_process_var[100];
int up_system_pid;
int update_successful;
struct timeval result, not1, not2;
int timeval_subtract (struct timeval *result,struct timeval *x,struct timeval *y){
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_usec < y->tv_usec) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_usec - y->tv_usec > 1000000) {
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}
/* Compute the time remaining to wait.
tv_usec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;
/* Return 1 if result is negative. */
if(x->tv_sec < y->tv_sec) return 1;
else return 0;
}
/************************************************************************************************/
/**
@brief Handles update notifications
Signal handler for system signal used for update notifications (normally SIGUSR2 but it can be chosen by developer).
It sets the flag that will be checked by update_point function so the update takes place at a safe moment of the execution.
So as dynamic updates are available the following line should be included in the source code:
signal(SIGUSR2,update_notification);
*/
void signal_handler(int sig, siginfo_t *siginfo, void *context)
{
if(up_system_pid == 0){
//Signal has been sent by the update sytem to notify an update
up_var->update_available=1;
//Get the pid of the update system that has just sent a signal
up_system_pid=(int)siginfo->si_pid;
//printf("New update available\n");
}
else {
//The signal has been sent by the new version process
update_successful=1;
}
}
void set_signal_handler(){
struct sigaction act;
memset (&act, '\0', sizeof(act));
act.sa_sigaction = &signal_handler;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
act.sa_flags = SA_SIGINFO;
sigaction(SIGUSR2,&act,NULL);
}
void check_update_status(){
//Build names of serialization files
sprintf(ser_up_var,"up_%s.ser",PROGRAM_NAME);
sprintf(ser_process_var,"pr_%s.ser",PROGRAM_NAME);
//Initialization
up_system_pid=0;
//printf("PN: %s Up: %s Process: %s\n",PROGRAM_NAME,ser_up_var,ser_process_var);
//Deserialization of update_variables.If not available, them initialize all
up_var=(update_variables *)malloc(sizeof(update_variables));
FILE *fp;
XDR xdrs;
fp=fopen(ser_up_var,"r");
if(fp==NULL)
{
//printf("No information from previous version\n");
up_var->update_available=0;
up_var->update_in_progress=0;
up_var->updated_from=0;
}
else
{
xdrstdio_create(&xdrs,fp, XDR_DECODE);
if(!xdr_update_variables(&xdrs,up_var))
{
printf("Up_var deserialization error\n");
up_var->update_available=0;
up_var->update_in_progress=0;
up_var->updated_from=0;
}
//else printf("Up_var correctly deserialized\n");
xdr_destroy (&xdrs);
fclose (fp);
remove(ser_up_var);
}
set_signal_handler();
}
void save_update_status(){
//printf("Up: %s Process: %s\n",ser_up_var,ser_process_var);
//Serialization of update_variables.
FILE *fp;
XDR xdrs;
fp=fopen(ser_up_var,"w");
xdrstdio_create(&xdrs,fp, XDR_ENCODE);
if(!xdr_update_variables(&xdrs,up_var))
{
printf("Up_var serialization error\n");
}
//else printf("Up_var correctly serialized\n");
xdr_destroy (&xdrs);
fclose (fp);
}
/*************************************************************************************************/
/**
@brief Manages data so that it can be modified as necessary for the execution of the new version
The prototype is defined here. However this function should be implemented by the developer.
The function receives a pointer to the struct containing data of the running version and returns a pointer to data necessary for the execution of the new version.
Modifications could include adding/removing/modifying variables or could simply do nothing.
@param old_data Pointer to the struct containing data of the running version
*/
void *restore_data(void *data);
int save_data(void *data);
/*************************************************************************************************/
/**
@brief Used as marker of safe update points
If the running process is a dynamic update that continues from this point it sets update_in_progress flag to 0.
If the running process is not a dynamic update, checks if there is a new update available and prepares its execution.
@param up_id Identifier of the update point from where the function is called
@param data Pointer to the struct containing the data of the old version
@returns 0 if update in progress, 1 if update available, 2 in any other case.
*/
void *update_point(int up_id, void **data){
char exec_new[100];
if(up_var->update_in_progress) { //check if it's here correctly, in this point
up_var->updated_from=0;
up_var->update_in_progress=0;
data=restore_data(data); //How to detect error to change flow here? Actually, the process stops itself
remove(ser_process_var);
//if ok then
//printf("Ok, inform old process pid %d\n",up_var->old_version_pid);
kill(up_var->old_version_pid,SIGUSR2);
//sleep(5);
return data;
}
if(up_var->update_available){
save_data(data); //It may fail
up_var->updated_from=up_id;
up_var->update_in_progress=1;
up_var->update_available=0;
up_var->old_version_pid=getpid();
update_successful=0;
save_update_status();
//sprintf(exec_new,"gnome-terminal ./up_2 &"); //Modified
sprintf(exec_new,"./%s &",PROGRAM_NAME);
//printf("Process %d .START NEW VERSION at point %d\n",up_var->old_version_pid,up_id);
gettimeofday(¬1,NULL);
system(exec_new);
sleep(10);
if(update_successful) {
//printf("SUCCESSFUL\n");
gettimeofday(¬2,NULL);
kill(up_system_pid,SIGUSR2);
timeval_subtract(&result,¬2,¬1);
printf("Update time:%ld.%06ld\n", result.tv_sec, result.tv_usec);
return NULL;}
else {
up_var->update_in_progress=0;
return data;
}
}
else
return data; //need another code for that???
}
#endif