aboutsummaryrefslogtreecommitdiff
path: root/portmidi/porttime/ptlinux.c
diff options
context:
space:
mode:
Diffstat (limited to 'portmidi/porttime/ptlinux.c')
-rwxr-xr-xportmidi/porttime/ptlinux.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/portmidi/porttime/ptlinux.c b/portmidi/porttime/ptlinux.c
new file mode 100755
index 0000000..c4af5c1
--- /dev/null
+++ b/portmidi/porttime/ptlinux.c
@@ -0,0 +1,139 @@
1/* ptlinux.c -- portable timer implementation for linux */
2
3
4/* IMPLEMENTATION NOTES (by Mark Nelson):
5
6Unlike Windows, Linux has no system call to request a periodic callback,
7so if Pt_Start() receives a callback parameter, it must create a thread
8that wakes up periodically and calls the provided callback function.
9If running as superuser, use setpriority() to renice thread to -20.
10One could also set the timer thread to a real-time priority (SCHED_FIFO
11and SCHED_RR), but this is dangerous for This is necessary because
12if the callback hangs it'll never return. A more serious reason
13is that the current scheduler implementation busy-waits instead
14of sleeping when realtime threads request a sleep of <=2ms (as a way
15to get around the 10ms granularity), which means the thread would never
16let anyone else on the CPU.
17
18CHANGE LOG
19
2018-Jul-03 Roger Dannenberg -- Simplified code to set priority of timer
21 thread. Simplified implementation notes.
22
23*/
24/* stdlib, stdio, unistd, and sys/types were added because they appeared
25 * in a Gentoo patch, but I'm not sure why they are needed. -RBD
26 */
27#include <stdlib.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <sys/types.h>
31#include "porttime.h"
32#include "time.h"
33#include "sys/resource.h"
34#include "pthread.h"
35
36#define TRUE 1
37#define FALSE 0
38
39#ifndef CLOCK_MONOTONIC_RAW
40#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
41#endif
42
43static int time_started_flag = FALSE;
44static struct timespec time_offset = {0, 0};
45static pthread_t pt_thread_pid;
46static int pt_thread_created = FALSE;
47
48/* note that this is static data -- we only need one copy */
49typedef struct {
50 int id;
51 int resolution;
52 PtCallback *callback;
53 void *userData;
54} pt_callback_parameters;
55
56static int pt_callback_proc_id = 0;
57
58static void *Pt_CallbackProc(void *p)
59{
60 pt_callback_parameters *parameters = (pt_callback_parameters *) p;
61 int mytime = 1;
62 /* to kill a process, just increment the pt_callback_proc_id */
63 /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id,
64 parameters->id); */
65 if (geteuid() == 0) setpriority(PRIO_PROCESS, 0, -20);
66 while (pt_callback_proc_id == parameters->id) {
67 /* wait for a multiple of resolution ms */
68 struct timeval timeout;
69 int delay = mytime++ * parameters->resolution - Pt_Time();
70 if (delay < 0) delay = 0;
71 timeout.tv_sec = 0;
72 timeout.tv_usec = delay * 1000;
73 select(0, NULL, NULL, NULL, &timeout);
74 (*(parameters->callback))(Pt_Time(), parameters->userData);
75 }
76 /* printf("Pt_CallbackProc exiting\n"); */
77 // free(parameters);
78 return NULL;
79}
80
81
82PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
83{
84 if (time_started_flag) return ptNoError;
85 /* need this set before process runs: */
86 clock_gettime(CLOCK_MONOTONIC_RAW, &time_offset);
87 if (callback) {
88 int res;
89 pt_callback_parameters *parms = (pt_callback_parameters *)
90 malloc(sizeof(pt_callback_parameters));
91 if (!parms) return ptInsufficientMemory;
92 parms->id = pt_callback_proc_id;
93 parms->resolution = resolution;
94 parms->callback = callback;
95 parms->userData = userData;
96 res = pthread_create(&pt_thread_pid, NULL,
97 Pt_CallbackProc, parms);
98 if (res != 0) return ptHostError;
99 pt_thread_created = TRUE;
100 }
101 time_started_flag = TRUE;
102 return ptNoError;
103}
104
105
106PtError Pt_Stop()
107{
108 /* printf("Pt_Stop called\n"); */
109 pt_callback_proc_id++;
110 if (pt_thread_created) {
111 pthread_join(pt_thread_pid, NULL);
112 pt_thread_created = FALSE;
113 }
114 time_started_flag = FALSE;
115 return ptNoError;
116}
117
118
119int Pt_Started()
120{
121 return time_started_flag;
122}
123
124
125PtTimestamp Pt_Time()
126{
127 long seconds, ms;
128 struct timespec now;
129 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
130 seconds = now.tv_sec - time_offset.tv_sec;
131 ms = (now.tv_nsec - time_offset.tv_nsec) / 1000000; /* round down */
132 return seconds * 1000 + ms;
133}
134
135
136void Pt_Sleep(int32_t duration)
137{
138 usleep(duration * 1000);
139}