33
33
#include <stdlib.h>
34
34
#include <signal.h>
35
35
#include <time.h>
36
+ #include <fcntl.h>
37
+ #include <unistd.h>
38
+ #include <errno.h>
39
+ #include <sys/syscall.h>
40
+ #include <sys/signalfd.h>
36
41
37
42
#include "vmmapi.h"
38
43
#include "inout.h"
39
44
#include "mc146818rtc.h"
40
45
#include "rtc.h"
46
+ #include "mevent.h"
41
47
42
48
/* #define DEBUG_RTC */
43
49
#ifdef DEBUG_RTC
@@ -70,6 +76,8 @@ struct rtcdev {
70
76
struct vrtc {
71
77
struct vmctx * vm ;
72
78
pthread_mutex_t mtx ;
79
+ int signal_fd ;
80
+ struct mevent * mevp ;
73
81
timer_t periodic_timer_id ; /*periodic timer id*/
74
82
timer_t update_timer_id ; /*update timer id*/
75
83
u_int addr ; /* RTC register to read or write */
@@ -115,6 +123,9 @@ struct clktime {
115
123
*/
116
124
#define VRTC_BROKEN_TIME ((time_t)-1)
117
125
126
+ /* signo of timers created by vrtc */
127
+ #define VRTC_TIMER_SIGNO SIGALRM
128
+
118
129
#define RTC_IRQ 8
119
130
#define RTCSB_BIN 0x04
120
131
#define RTCSB_ALL_INTRS (RTCSB_UINTR | RTCSB_AINTR | RTCSB_PINTR)
@@ -564,30 +575,29 @@ rtc_to_secs(struct vrtc *vrtc)
564
575
return VRTC_BROKEN_TIME ;
565
576
}
566
577
567
- static timer_t
568
- vrtc_create_timer (struct vrtc * vrtc , time_t sec , time_t nsec , void ( * cb )() )
578
+ static void
579
+ vrtc_create_timer (timer_t * timer_id , time_t sec , time_t nsec )
569
580
{
570
- timer_t timerid ;
571
581
struct sigevent sigevt ;
572
582
struct itimerspec ts ;
573
583
574
584
memset (& sigevt , 0 , sizeof (struct sigevent ));
575
585
memset (& ts , 0 , sizeof (struct itimerspec ));
576
586
577
- sigevt .sigev_value .sival_ptr = vrtc ;
578
- sigevt .sigev_notify = SIGEV_THREAD ;
579
- sigevt .sigev_notify_function = cb ;
587
+ /* there is no glibc wrapper for gettid */
588
+ sigevt ._sigev_un ._tid = syscall (SYS_gettid );
589
+ sigevt .sigev_value .sival_ptr = timer_id ;
590
+ sigevt .sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL ;
591
+ sigevt .sigev_signo = VRTC_TIMER_SIGNO ;
580
592
581
- assert (timer_create (CLOCK_REALTIME , & sigevt , & timerid ) == 0 );
593
+ assert (timer_create (CLOCK_REALTIME , & sigevt , timer_id ) == 0 );
582
594
/*setting the interval time*/
583
595
ts .it_interval .tv_sec = sec ;
584
596
ts .it_interval .tv_nsec = nsec ;
585
597
/*set the delay time it will be started when timer_setting*/
586
598
ts .it_value .tv_sec = sec ;
587
599
ts .it_value .tv_nsec = nsec ;
588
- assert (timer_settime (timerid , 0 , & ts , NULL ) == 0 );
589
-
590
- return timerid ;
600
+ assert (timer_settime (* timer_id , 0 , & ts , NULL ) == 0 );
591
601
}
592
602
593
603
static void
@@ -811,8 +821,7 @@ vrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval)
811
821
}
812
822
813
823
/*create the new periodic timer*/
814
- vrtc -> periodic_timer_id =
815
- vrtc_create_timer (vrtc , 0 , newfreq , vrtc_periodic_timer );
824
+ vrtc_create_timer (& vrtc -> periodic_timer_id , 0 , newfreq );
816
825
assert (vrtc -> periodic_timer_id > 0 );
817
826
818
827
} else {
@@ -873,8 +882,7 @@ vrtc_set_reg_a(struct vrtc *vrtc, uint8_t newval)
873
882
}
874
883
875
884
/*create the new periodic timer*/
876
- vrtc -> periodic_timer_id =
877
- vrtc_create_timer (vrtc , 0 , newfreq , vrtc_periodic_timer );
885
+ vrtc_create_timer (& vrtc -> periodic_timer_id , 0 , newfreq );
878
886
assert (vrtc -> periodic_timer_id > 0 );
879
887
} else {
880
888
/*Nothing to do*/
@@ -1100,12 +1108,49 @@ vrtc_enable_localtime(int l_time)
1100
1108
local_time = l_time ;
1101
1109
}
1102
1110
1111
+ static void
1112
+ vrtc_handle_timer (int fd __attribute__((unused )),
1113
+ enum ev_type t __attribute__((unused )),
1114
+ void * arg )
1115
+ {
1116
+ struct vrtc * vrtc = arg ;
1117
+ struct signalfd_siginfo info ;
1118
+ timer_t * timer_id ;
1119
+ int len ;
1120
+
1121
+ while (1 ) {
1122
+ len = read (vrtc -> signal_fd , & info , sizeof (info ));
1123
+ if (len == -1 && errno == EAGAIN )
1124
+ break ;
1125
+ if (len == -1 ) {
1126
+ RTC_DEBUG ("signal_fd read failed: error = %d\n" ,
1127
+ errno );
1128
+ break ;
1129
+ }
1130
+ if (len != sizeof (info )) {
1131
+ RTC_DEBUG ("signal_fd read len error: len = %d\n" ,
1132
+ len );
1133
+ break ;
1134
+ }
1135
+
1136
+ timer_id = (timer_t * )info .ssi_ptr ;
1137
+ if (* timer_id == vrtc -> update_timer_id )
1138
+ vrtc_update_timer (vrtc );
1139
+ else if (* timer_id == vrtc -> periodic_timer_id )
1140
+ vrtc_periodic_timer (vrtc );
1141
+ else
1142
+ RTC_DEBUG ("unsupported timer_id 0xlx\n" , * timer_id );
1143
+ }
1144
+ }
1145
+
1103
1146
int
1104
1147
vrtc_init (struct vmctx * ctx )
1105
1148
{
1106
1149
struct vrtc * vrtc ;
1107
1150
struct rtcdev * rtc ;
1108
1151
time_t curtime ;
1152
+ sigset_t mask ;
1153
+ int flags ;
1109
1154
struct inout_port rtc_addr , rtc_data ;
1110
1155
1111
1156
vrtc = calloc (1 , sizeof (struct vrtc ));
@@ -1115,11 +1160,6 @@ vrtc_init(struct vmctx *ctx)
1115
1160
1116
1161
pthread_mutex_init (& vrtc -> mtx , NULL );
1117
1162
1118
- /*create update interrupt timer(1s)*/
1119
- vrtc -> update_timer_id =
1120
- vrtc_create_timer (vrtc , 1 , 0 , vrtc_update_timer );
1121
- assert (vrtc -> update_timer_id > 0 );
1122
-
1123
1163
memset (& rtc_addr , 0 , sizeof (struct inout_port ));
1124
1164
memset (& rtc_data , 0 , sizeof (struct inout_port ));
1125
1165
/*register io port handler for rtc addr*/
@@ -1162,6 +1202,31 @@ vrtc_init(struct vmctx *ctx)
1162
1202
secs_to_rtc (curtime , vrtc , 0 );
1163
1203
pthread_mutex_unlock (& vrtc -> mtx );
1164
1204
1205
+ /*block VRTC_TIMER_SIGNO so it can be polled by signalfd*/
1206
+ sigemptyset (& mask );
1207
+ sigaddset (& mask , VRTC_TIMER_SIGNO );
1208
+ pthread_sigmask (SIG_BLOCK , & mask , NULL );
1209
+
1210
+ /*create signalfd*/
1211
+ vrtc -> signal_fd = signalfd (-1 , & mask , 0 );
1212
+ assert (vrtc -> signal_fd > 0 );
1213
+
1214
+ /*set close-on-exec*/
1215
+ flags = fcntl (vrtc -> signal_fd , F_GETFD );
1216
+ fcntl (vrtc -> signal_fd , F_SETFD , flags | FD_CLOEXEC );
1217
+
1218
+ /*set non-block*/
1219
+ flags = fcntl (vrtc -> signal_fd , F_GETFL );
1220
+ fcntl (vrtc -> signal_fd , F_SETFL , flags | O_NONBLOCK );
1221
+
1222
+ vrtc -> mevp = mevent_add (vrtc -> signal_fd , EVF_READ ,
1223
+ vrtc_handle_timer , vrtc );
1224
+ assert (vrtc -> mevp != NULL );
1225
+
1226
+ /*create update interrupt timer(1s)*/
1227
+ vrtc_create_timer (& vrtc -> update_timer_id , 1 , 0 );
1228
+ assert (vrtc -> update_timer_id > 0 );
1229
+
1165
1230
return 0 ;
1166
1231
}
1167
1232
@@ -1170,6 +1235,29 @@ vrtc_deinit(struct vmctx *ctx)
1170
1235
{
1171
1236
struct vrtc * vrtc = ctx -> vrtc ;
1172
1237
struct inout_port iop ;
1238
+ sig_t prev_sig_handler ;
1239
+
1240
+ /*delete timer*/
1241
+ if (vrtc -> update_timer_id > 0 ) {
1242
+ vrtc_delete_timer (vrtc -> update_timer_id );
1243
+ vrtc -> update_timer_id = (timer_t )- 1 ;
1244
+ }
1245
+
1246
+ if (vrtc -> periodic_timer_id > 0 ) {
1247
+ vrtc_delete_timer (vrtc -> periodic_timer_id );
1248
+ vrtc -> periodic_timer_id = (timer_t )- 1 ;
1249
+ }
1250
+
1251
+ if (vrtc -> mevp )
1252
+ mevent_delete (vrtc -> mevp );
1253
+
1254
+ if (vrtc -> signal_fd > 0 )
1255
+ close (vrtc -> signal_fd );
1256
+
1257
+ /*clear pending signals*/
1258
+ prev_sig_handler = signal (VRTC_TIMER_SIGNO , SIG_IGN );
1259
+ if (prev_sig_handler != SIG_ERR )
1260
+ signal (VRTC_TIMER_SIGNO , prev_sig_handler );
1173
1261
1174
1262
memset (& iop , 0 , sizeof (struct inout_port ));
1175
1263
iop .name = "rtc" ;
@@ -1183,7 +1271,6 @@ vrtc_deinit(struct vmctx *ctx)
1183
1271
iop .size = 1 ;
1184
1272
unregister_inout (& iop );
1185
1273
1186
- vrtc_delete_timer (vrtc -> update_timer_id );
1187
1274
free (vrtc );
1188
1275
ctx -> vrtc = NULL ;
1189
1276
}
0 commit comments