diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-07 06:50:04 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-07 06:50:04 +0200 |
| commit | 988f5d2b5343850e19ad1512cefe6c53953aa02e (patch) | |
| tree | 1ff29934294e73b2575488c06df91866ce251dbe /portmidi/porttime/ptlinux.c | |
| parent | 9b5839c58a2e1df8bddf6b98805998508ea417d5 (diff) | |
| download | ttdaw-988f5d2b5343850e19ad1512cefe6c53953aa02e.tar.gz | |
Added bunch of examples
Diffstat (limited to 'portmidi/porttime/ptlinux.c')
| -rwxr-xr-x | portmidi/porttime/ptlinux.c | 139 |
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 | |||
| 6 | Unlike Windows, Linux has no system call to request a periodic callback, | ||
| 7 | so if Pt_Start() receives a callback parameter, it must create a thread | ||
| 8 | that wakes up periodically and calls the provided callback function. | ||
| 9 | If running as superuser, use setpriority() to renice thread to -20. | ||
| 10 | One could also set the timer thread to a real-time priority (SCHED_FIFO | ||
| 11 | and SCHED_RR), but this is dangerous for This is necessary because | ||
| 12 | if the callback hangs it'll never return. A more serious reason | ||
| 13 | is that the current scheduler implementation busy-waits instead | ||
| 14 | of sleeping when realtime threads request a sleep of <=2ms (as a way | ||
| 15 | to get around the 10ms granularity), which means the thread would never | ||
| 16 | let anyone else on the CPU. | ||
| 17 | |||
| 18 | CHANGE LOG | ||
| 19 | |||
| 20 | 18-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 | |||
| 43 | static int time_started_flag = FALSE; | ||
| 44 | static struct timespec time_offset = {0, 0}; | ||
| 45 | static pthread_t pt_thread_pid; | ||
| 46 | static int pt_thread_created = FALSE; | ||
| 47 | |||
| 48 | /* note that this is static data -- we only need one copy */ | ||
| 49 | typedef struct { | ||
| 50 | int id; | ||
| 51 | int resolution; | ||
| 52 | PtCallback *callback; | ||
| 53 | void *userData; | ||
| 54 | } pt_callback_parameters; | ||
| 55 | |||
| 56 | static int pt_callback_proc_id = 0; | ||
| 57 | |||
| 58 | static 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 | |||
| 82 | PtError 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 | |||
| 106 | PtError 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 | |||
| 119 | int Pt_Started() | ||
| 120 | { | ||
| 121 | return time_started_flag; | ||
| 122 | } | ||
| 123 | |||
| 124 | |||
| 125 | PtTimestamp 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 | |||
| 136 | void Pt_Sleep(int32_t duration) | ||
| 137 | { | ||
| 138 | usleep(duration * 1000); | ||
| 139 | } | ||
