Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/alsa/utimer-test.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* This test covers the functionality of userspace-driven ALSA timers. Such timers
4
* are purely virtual (so they don't directly depend on the hardware), and they could be
5
* created and triggered by userspace applications.
6
*
7
* Author: Ivan Orlov <[email protected]>
8
*/
9
#include "../kselftest_harness.h"
10
#include <sound/asound.h>
11
#include <unistd.h>
12
#include <fcntl.h>
13
#include <limits.h>
14
#include <sys/ioctl.h>
15
#include <stdlib.h>
16
#include <pthread.h>
17
#include <string.h>
18
19
#define FRAME_RATE 8000
20
#define PERIOD_SIZE 4410
21
#define UTIMER_DEFAULT_ID -1
22
#define UTIMER_DEFAULT_FD -1
23
#define NANO 1000000000ULL
24
#define TICKS_COUNT 10
25
#define TICKS_RECORDING_DELTA 5
26
#define TIMER_OUTPUT_BUF_LEN 1024
27
#define TIMER_FREQ_SEC 1
28
#define RESULT_PREFIX_LEN strlen("Total ticks count: ")
29
30
enum timer_app_event {
31
TIMER_APP_STARTED,
32
TIMER_APP_RESULT,
33
TIMER_NO_EVENT,
34
};
35
36
FIXTURE(timer_f) {
37
struct snd_timer_uinfo *utimer_info;
38
};
39
40
FIXTURE_SETUP(timer_f) {
41
int timer_dev_fd;
42
43
if (geteuid())
44
SKIP(return, "This test needs root to run!");
45
46
self->utimer_info = calloc(1, sizeof(*self->utimer_info));
47
ASSERT_NE(NULL, self->utimer_info);
48
49
/* Resolution is the time the period of frames takes in nanoseconds */
50
self->utimer_info->resolution = (NANO / FRAME_RATE * PERIOD_SIZE);
51
52
timer_dev_fd = open("/dev/snd/timer", O_RDONLY);
53
ASSERT_GE(timer_dev_fd, 0);
54
55
ASSERT_EQ(ioctl(timer_dev_fd, SNDRV_TIMER_IOCTL_CREATE, self->utimer_info), 0);
56
ASSERT_GE(self->utimer_info->fd, 0);
57
58
close(timer_dev_fd);
59
}
60
61
FIXTURE_TEARDOWN(timer_f) {
62
close(self->utimer_info->fd);
63
free(self->utimer_info);
64
}
65
66
static void *ticking_func(void *data)
67
{
68
int i;
69
int *fd = (int *)data;
70
71
for (i = 0; i < TICKS_COUNT; i++) {
72
/* Well, trigger the timer! */
73
ioctl(*fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL);
74
sleep(TIMER_FREQ_SEC);
75
}
76
77
return NULL;
78
}
79
80
static enum timer_app_event parse_timer_output(const char *s)
81
{
82
if (strstr(s, "Timer has started"))
83
return TIMER_APP_STARTED;
84
if (strstr(s, "Total ticks count"))
85
return TIMER_APP_RESULT;
86
87
return TIMER_NO_EVENT;
88
}
89
90
static int parse_timer_result(const char *s)
91
{
92
char *end;
93
long d;
94
95
d = strtol(s + RESULT_PREFIX_LEN, &end, 10);
96
if (end == s + RESULT_PREFIX_LEN)
97
return -1;
98
99
return d;
100
}
101
102
/*
103
* This test triggers the timer and counts ticks at the same time. The amount
104
* of the timer trigger calls should be equal to the amount of ticks received.
105
*/
106
TEST_F(timer_f, utimer) {
107
char command[64];
108
pthread_t ticking_thread;
109
int total_ticks = 0;
110
FILE *rfp;
111
char *buf = malloc(TIMER_OUTPUT_BUF_LEN);
112
113
ASSERT_NE(buf, NULL);
114
115
/* The timeout should be the ticks interval * count of ticks + some delta */
116
sprintf(command, "./global-timer %d %d %d", SNDRV_TIMER_GLOBAL_UDRIVEN,
117
self->utimer_info->id, TICKS_COUNT * TIMER_FREQ_SEC + TICKS_RECORDING_DELTA);
118
119
rfp = popen(command, "r");
120
while (fgets(buf, TIMER_OUTPUT_BUF_LEN, rfp)) {
121
buf[TIMER_OUTPUT_BUF_LEN - 1] = 0;
122
switch (parse_timer_output(buf)) {
123
case TIMER_APP_STARTED:
124
/* global-timer waits for timer to trigger, so start the ticking thread */
125
pthread_create(&ticking_thread, NULL, ticking_func,
126
&self->utimer_info->fd);
127
break;
128
case TIMER_APP_RESULT:
129
total_ticks = parse_timer_result(buf);
130
break;
131
case TIMER_NO_EVENT:
132
break;
133
}
134
}
135
pthread_join(ticking_thread, NULL);
136
ASSERT_EQ(total_ticks, TICKS_COUNT);
137
pclose(rfp);
138
free(buf);
139
}
140
141
TEST(wrong_timers_test) {
142
int timer_dev_fd;
143
int utimer_fd;
144
size_t i;
145
struct snd_timer_uinfo wrong_timer = {
146
.resolution = 0,
147
.id = UTIMER_DEFAULT_ID,
148
.fd = UTIMER_DEFAULT_FD,
149
};
150
151
timer_dev_fd = open("/dev/snd/timer", O_RDONLY);
152
ASSERT_GE(timer_dev_fd, 0);
153
154
utimer_fd = ioctl(timer_dev_fd, SNDRV_TIMER_IOCTL_CREATE, &wrong_timer);
155
ASSERT_LT(utimer_fd, 0);
156
/* Check that id was not updated */
157
ASSERT_EQ(wrong_timer.id, UTIMER_DEFAULT_ID);
158
159
/* Test the NULL as an argument is processed correctly */
160
ASSERT_LT(ioctl(timer_dev_fd, SNDRV_TIMER_IOCTL_CREATE, NULL), 0);
161
162
close(timer_dev_fd);
163
}
164
165
TEST_HARNESS_MAIN
166
167