LCOV - code coverage report
Current view: top level - core - pt_compat.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 51 55 92.7 %
Date: 2026-02-22 12:14:12 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /**
       2             :  * @file pt_compat.c
       3             :  * @brief Cross-platform compatibility layer implementation
       4             :  */
       5             : 
       6             : #include "pt_compat.h"
       7             : 
       8             : #if defined(PT_PLATFORM_POSIX)
       9             :     #include <stdlib.h>
      10             :     #include <string.h>
      11             :     #include <stdio.h>
      12             :     #include <time.h>  /* For clock_gettime in pt_get_ticks */
      13             : #elif defined(PT_PLATFORM_MACTCP) || defined(PT_PLATFORM_OT)
      14             :     #include <MacMemory.h>
      15             :     #ifdef PT_PLATFORM_OT
      16             :         #include <OpenTransport.h>
      17             :     #endif
      18             : #endif
      19             : 
      20             : /* ========================================================================== */
      21             : /* Memory Allocation - POSIX                                                  */
      22             : /* ========================================================================== */
      23             : 
      24             : #if defined(PT_PLATFORM_POSIX)
      25             : 
      26         215 : void *pt_alloc(size_t size) {
      27         215 :     return malloc(size);
      28             : }
      29             : 
      30         633 : void pt_free(void *ptr) {
      31         633 :     free(ptr);
      32         633 : }
      33             : 
      34         635 : void *pt_alloc_clear(size_t size) {
      35         635 :     return calloc(1, size);
      36             : }
      37             : 
      38           1 : size_t pt_get_free_mem(void) {
      39             :     /* POSIX: return effectively unlimited */
      40           1 :     return 1024UL * 1024UL * 1024UL; /* 1GB */
      41             : }
      42             : 
      43           1 : size_t pt_get_max_block(void) {
      44             :     /* POSIX: return effectively unlimited */
      45           1 :     return 1024UL * 1024UL * 1024UL; /* 1GB */
      46             : }
      47             : 
      48             : #endif /* PT_PLATFORM_POSIX */
      49             : 
      50             : /* ========================================================================== */
      51             : /* Memory Allocation - Classic Mac                                            */
      52             : /* ========================================================================== */
      53             : 
      54             : #if defined(PT_PLATFORM_MACTCP) || defined(PT_PLATFORM_OT)
      55             : 
      56             : void *pt_alloc(size_t size) {
      57             :     return NewPtr((Size)size);
      58             : }
      59             : 
      60             : void pt_free(void *ptr) {
      61             :     if (ptr != NULL) {
      62             :         DisposePtr((Ptr)ptr);
      63             :     }
      64             : }
      65             : 
      66             : void *pt_alloc_clear(size_t size) {
      67             :     return NewPtrClear((Size)size);
      68             : }
      69             : 
      70             : size_t pt_get_free_mem(void) {
      71             :     return (size_t)FreeMem();
      72             : }
      73             : 
      74             : size_t pt_get_max_block(void) {
      75             :     return (size_t)MaxBlock();
      76             : }
      77             : 
      78             : #endif /* PT_PLATFORM_MACTCP || PT_PLATFORM_OT */
      79             : 
      80             : /* ========================================================================== */
      81             : /* Atomic Operations - POSIX                                                  */
      82             : /* ========================================================================== */
      83             : 
      84             : #if defined(PT_PLATFORM_POSIX)
      85             : 
      86             : /**
      87             :  * IMPORTANT: POSIX 'atomic' operations - NOT thread-safe for true
      88             :  * multi-threading!
      89             :  *
      90             :  * PeerTalk uses a single-threaded, non-blocking event loop model.
      91             :  * These volatile operations are sufficient for that use case.
      92             :  *
      93             :  * For applications that use PeerTalk from multiple threads, external
      94             :  * synchronization (e.g., pthread_mutex) is required around PeerTalk
      95             :  * API calls.
      96             :  */
      97             : 
      98           2 : void pt_atomic_set_bit(pt_atomic_t *flags, int bit) {
      99           2 :     *flags |= (1U << bit);
     100           2 : }
     101             : 
     102           1 : void pt_atomic_clear_bit(pt_atomic_t *flags, int bit) {
     103           1 :     *flags &= ~(1U << bit);
     104           1 : }
     105             : 
     106           7 : int pt_atomic_test_bit(const pt_atomic_t *flags, int bit) {
     107           7 :     return (*flags & (1U << bit)) != 0;
     108             : }
     109             : 
     110           2 : int pt_atomic_test_and_clear_bit(pt_atomic_t *flags, int bit) {
     111           2 :     uint32_t mask = (1U << bit);
     112           2 :     int was_set = (*flags & mask) != 0;
     113           2 :     *flags &= ~mask;
     114           2 :     return was_set;
     115             : }
     116             : 
     117             : #endif /* PT_PLATFORM_POSIX */
     118             : 
     119             : /* ========================================================================== */
     120             : /* Atomic Operations - MacTCP (68k)                                           */
     121             : /* ========================================================================== */
     122             : 
     123             : #if defined(PT_PLATFORM_MACTCP)
     124             : 
     125             : /**
     126             :  * 68k atomic operations using volatile.
     127             :  *
     128             :  * Safe because:
     129             :  * 1. ASR only SETS bits (via OR): *flags |= mask
     130             :  * 2. Main loop only CLEARS bits (via AND): *flags &= ~mask
     131             :  * 3. No read-modify-write race (operations are one-way)
     132             :  * 4. 32-bit aligned access is atomic on 68000+ (hardware guarantee)
     133             :  *
     134             :  * Based on Motorola 68000 User's Manual, Section 8:
     135             :  * "32-bit aligned accesses complete in a single bus cycle and cannot
     136             :  * be interrupted mid-operation."
     137             :  *
     138             :  * Does NOT disable interrupts - unnecessary for this pattern.
     139             :  */
     140             : 
     141             : void pt_atomic_set_bit(pt_atomic_t *flags, int bit) {
     142             :     *flags |= (1U << bit);
     143             : }
     144             : 
     145             : void pt_atomic_clear_bit(pt_atomic_t *flags, int bit) {
     146             :     *flags &= ~(1U << bit);
     147             : }
     148             : 
     149             : int pt_atomic_test_bit(const pt_atomic_t *flags, int bit) {
     150             :     return (*flags & (1U << bit)) != 0;
     151             : }
     152             : 
     153             : int pt_atomic_test_and_clear_bit(pt_atomic_t *flags, int bit) {
     154             :     uint32_t mask = (1U << bit);
     155             :     int was_set = (*flags & mask) != 0;
     156             :     *flags &= ~mask;
     157             :     return was_set;
     158             : }
     159             : 
     160             : #endif /* PT_PLATFORM_MACTCP */
     161             : 
     162             : /* ========================================================================== */
     163             : /* Atomic Operations - Open Transport (PPC)                                   */
     164             : /* ========================================================================== */
     165             : 
     166             : #if defined(PT_PLATFORM_OT)
     167             : 
     168             : /**
     169             :  * Open Transport atomic operations using OTAtomic* functions.
     170             :  *
     171             :  * OTAtomic functions operate on BYTES with bit indices 0-7.
     172             :  * For a 32-bit flags word, we need to calculate which byte contains
     173             :  * the bit we want to manipulate.
     174             :  *
     175             :  * Big-endian byte layout (32-bit word at address 0x1000):
     176             :  *   0x1000: byte 0 (bits 24-31) - OT bits 0-7
     177             :  *   0x1001: byte 1 (bits 16-23) - OT bits 0-7
     178             :  *   0x1002: byte 2 (bits 8-15)  - OT bits 0-7
     179             :  *   0x1003: byte 3 (bits 0-7)   - OT bits 0-7
     180             :  *
     181             :  * To set logical bit N (0-31):
     182             :  *   byte_offset = 3 - (N / 8)
     183             :  *   bit_in_byte = N % 8
     184             :  */
     185             : 
     186             : void pt_atomic_set_bit(pt_atomic_t *flags, int bit) {
     187             :     int byte_offset = 3 - (bit / 8);
     188             :     int bit_in_byte = bit % 8;
     189             :     UInt8 *byte_ptr = ((UInt8 *)flags) + byte_offset;
     190             :     OTAtomicSetBit(byte_ptr, (UInt8)bit_in_byte);
     191             : }
     192             : 
     193             : void pt_atomic_clear_bit(pt_atomic_t *flags, int bit) {
     194             :     int byte_offset = 3 - (bit / 8);
     195             :     int bit_in_byte = bit % 8;
     196             :     UInt8 *byte_ptr = ((UInt8 *)flags) + byte_offset;
     197             :     OTAtomicClearBit(byte_ptr, (UInt8)bit_in_byte);
     198             : }
     199             : 
     200             : int pt_atomic_test_bit(pt_atomic_t *flags, int bit) {
     201             :     int byte_offset = 3 - (bit / 8);
     202             :     int bit_in_byte = bit % 8;
     203             :     UInt8 *byte_ptr = ((UInt8 *)flags) + byte_offset;
     204             :     return OTAtomicTestBit(byte_ptr, (UInt8)bit_in_byte);
     205             : }
     206             : 
     207             : int pt_atomic_test_and_clear_bit(pt_atomic_t *flags, int bit) {
     208             :     int byte_offset = 3 - (bit / 8);
     209             :     int bit_in_byte = bit % 8;
     210             :     UInt8 *byte_ptr = ((UInt8 *)flags) + byte_offset;
     211             :     Boolean was_set = OTAtomicTestBit(byte_ptr, (UInt8)bit_in_byte);
     212             :     if (was_set) {
     213             :         OTAtomicClearBit(byte_ptr, (UInt8)bit_in_byte);
     214             :     }
     215             :     return was_set ? 1 : 0;
     216             : }
     217             : 
     218             : #endif /* PT_PLATFORM_OT */
     219             : 
     220             : /* ========================================================================== */
     221             : /* Memory Utilities - POSIX                                                   */
     222             : /* ========================================================================== */
     223             : 
     224             : #if defined(PT_PLATFORM_POSIX)
     225             : 
     226       21727 : void *pt_memcpy(void *dest, const void *src, size_t n) {
     227       21727 :     return memcpy(dest, src, n);
     228             : }
     229             : 
     230        1124 : void *pt_memset(void *dest, int c, size_t n) {
     231        1124 :     return memset(dest, c, n);
     232             : }
     233             : 
     234           3 : int pt_memcmp(const void *a, const void *b, size_t n) {
     235           3 :     return memcmp(a, b, n);
     236             : }
     237             : 
     238           0 : void *pt_memmove(void *dest, const void *src, size_t n) {
     239           0 :     return memmove(dest, src, n);
     240             : }
     241             : 
     242          88 : size_t pt_strlen(const char *s) {
     243          88 :     return strlen(s);
     244             : }
     245             : 
     246          53 : char *pt_strncpy(char *dest, const char *src, size_t n) {
     247          53 :     strncpy(dest, src, n);
     248          53 :     if (n > 0) {
     249          53 :         dest[n - 1] = '\0'; /* Always null-terminate */
     250             :     }
     251          53 :     return dest;
     252             : }
     253             : 
     254             : #endif /* PT_PLATFORM_POSIX */
     255             : 
     256             : /* ========================================================================== */
     257             : /* Memory Utilities - Classic Mac                                             */
     258             : /* ========================================================================== */
     259             : 
     260             : #if defined(PT_PLATFORM_MACTCP) || defined(PT_PLATFORM_OT)
     261             : 
     262             : void *pt_memcpy(void *dest, const void *src, size_t n) {
     263             :     BlockMoveData(src, dest, (Size)n);
     264             :     return dest;
     265             : }
     266             : 
     267             : void *pt_memset(void *dest, int c, size_t n) {
     268             :     unsigned char *p = (unsigned char *)dest;
     269             :     unsigned char value = (unsigned char)c;
     270             :     size_t i;
     271             :     for (i = 0; i < n; i++) {
     272             :         p[i] = value;
     273             :     }
     274             :     return dest;
     275             : }
     276             : 
     277             : int pt_memcmp(const void *a, const void *b, size_t n) {
     278             :     const unsigned char *pa = (const unsigned char *)a;
     279             :     const unsigned char *pb = (const unsigned char *)b;
     280             :     size_t i;
     281             :     for (i = 0; i < n; i++) {
     282             :         if (pa[i] != pb[i]) {
     283             :             return (pa[i] < pb[i]) ? -1 : 1;
     284             :         }
     285             :     }
     286             :     return 0;
     287             : }
     288             : 
     289             : void *pt_memmove(void *dest, const void *src, size_t n) {
     290             :     unsigned char *d = (unsigned char *)dest;
     291             :     const unsigned char *s = (const unsigned char *)src;
     292             : 
     293             :     if (d == s || n == 0) {
     294             :         return dest;
     295             :     }
     296             : 
     297             :     if (d < s) {
     298             :         /* Forward copy (no overlap or dest before src) */
     299             :         size_t i;
     300             :         for (i = 0; i < n; i++) {
     301             :             d[i] = s[i];
     302             :         }
     303             :     } else {
     304             :         /* Backward copy (dest after src, may overlap) */
     305             :         size_t i = n;
     306             :         while (i > 0) {
     307             :             i--;
     308             :             d[i] = s[i];
     309             :         }
     310             :     }
     311             :     return dest;
     312             : }
     313             : 
     314             : size_t pt_strlen(const char *s) {
     315             :     size_t len = 0;
     316             :     while (*s++) {
     317             :         len++;
     318             :     }
     319             :     return len;
     320             : }
     321             : 
     322             : char *pt_strncpy(char *dest, const char *src, size_t n) {
     323             :     size_t i;
     324             :     for (i = 0; i < n && src[i] != '\0'; i++) {
     325             :         dest[i] = src[i];
     326             :     }
     327             :     /* Pad with nulls if src is shorter than n */
     328             :     for (; i < n; i++) {
     329             :         dest[i] = '\0';
     330             :     }
     331             :     /* Always null-terminate if buffer size > 0 */
     332             :     if (n > 0) {
     333             :         dest[n - 1] = '\0';
     334             :     }
     335             :     return dest;
     336             : }
     337             : 
     338             : #endif /* PT_PLATFORM_MACTCP || PT_PLATFORM_OT */
     339             : 
     340             : /* ========================================================================== */
     341             : /* ISR-Safe Memory Copy (All Platforms)                                       */
     342             : /* ========================================================================== */
     343             : 
     344           2 : void *pt_memcpy_isr(void *dest, const void *src, size_t n) {
     345           2 :     unsigned char *d = (unsigned char *)dest;
     346           2 :     const unsigned char *s = (const unsigned char *)src;
     347             :     size_t i;
     348          21 :     for (i = 0; i < n; i++) {
     349          19 :         d[i] = s[i];
     350             :     }
     351           2 :     return dest;
     352             : }
     353             : 
     354             : /* ========================================================================== */
     355             : /* Formatted Output - POSIX                                                   */
     356             : /* ========================================================================== */
     357             : 
     358             : #if defined(PT_PLATFORM_POSIX)
     359             : 
     360           0 : int pt_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) {
     361           0 :     return vsnprintf(buf, size, fmt, args);
     362             : }
     363             : 
     364          18 : int pt_snprintf(char *buf, size_t size, const char *fmt, ...) {
     365             :     va_list args;
     366             :     int result;
     367          18 :     va_start(args, fmt);
     368          18 :     result = vsnprintf(buf, size, fmt, args);
     369          18 :     va_end(args);
     370          18 :     return result;
     371             : }
     372             : 
     373             : #endif /* PT_PLATFORM_POSIX */
     374             : 
     375             : /* ========================================================================== */
     376             : /* Formatted Output - Classic Mac (Limited Implementation)                    */
     377             : /* ========================================================================== */
     378             : 
     379             : #if defined(PT_PLATFORM_MACTCP) || defined(PT_PLATFORM_OT)
     380             : 
     381             : /**
     382             :  * Helper: Format an integer to a string buffer.
     383             :  * @param value Integer value
     384             :  * @param base Base (10 or 16)
     385             :  * @param width Field width (0 = no padding)
     386             :  * @param zero_pad 1 to pad with zeros, 0 to pad with spaces
     387             :  * @param uppercase 1 for uppercase hex (A-F), 0 for lowercase (a-f)
     388             :  * @param is_signed 1 if value should be treated as signed
     389             :  * @param buf Output buffer
     390             :  * @param bufsize Size of output buffer
     391             :  * @return Number of characters written
     392             :  */
     393             : static int pt_format_int(long value, int base, int width, int zero_pad,
     394             :                          int uppercase, int is_signed, char *buf,
     395             :                          size_t bufsize) {
     396             :     char temp[32];
     397             :     int len = 0;
     398             :     int negative = 0;
     399             :     unsigned long uvalue;
     400             :     const char *digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
     401             : 
     402             :     if (bufsize == 0) return 0;
     403             : 
     404             :     /* Handle signed values */
     405             :     if (is_signed && value < 0) {
     406             :         negative = 1;
     407             :         uvalue = (unsigned long)(-value);
     408             :     } else {
     409             :         uvalue = (unsigned long)value;
     410             :     }
     411             : 
     412             :     /* Convert to string (reversed) */
     413             :     if (uvalue == 0) {
     414             :         temp[len++] = '0';
     415             :     } else {
     416             :         while (uvalue > 0 && len < (int)sizeof(temp)) {
     417             :             /* cppcheck-suppress zerodivcond ; base is always 10 or 16 from callers */
     418             :             temp[len++] = digits[uvalue % base];
     419             :             uvalue /= base;
     420             :         }
     421             :     }
     422             : 
     423             :     /* Add sign if negative */
     424             :     if (negative) {
     425             :         temp[len++] = '-';
     426             :     }
     427             : 
     428             :     /* Calculate padding */
     429             :     int pad = width - len;
     430             :     if (pad < 0) pad = 0;
     431             : 
     432             :     int pos = 0;
     433             : 
     434             :     /* Pad with spaces (if not zero-padding) */
     435             :     if (!zero_pad) {
     436             :         while (pad > 0 && pos < (int)bufsize - 1) {
     437             :             buf[pos++] = ' ';
     438             :             pad--;
     439             :         }
     440             :     }
     441             : 
     442             :     /* If zero-padding and negative, write sign first */
     443             :     if (zero_pad && negative && pos < (int)bufsize - 1) {
     444             :         buf[pos++] = '-';
     445             :         len--; /* Sign already written */
     446             :     }
     447             : 
     448             :     /* Pad with zeros */
     449             :     if (zero_pad) {
     450             :         while (pad > 0 && pos < (int)bufsize - 1) {
     451             :             buf[pos++] = '0';
     452             :             pad--;
     453             :         }
     454             :     }
     455             : 
     456             :     /* Write digits (reversed) */
     457             :     int start = negative && zero_pad ? 1 : (negative ? 1 : 0);
     458             :     for (int i = len - 1; i >= start && pos < (int)bufsize - 1; i--) {
     459             :         buf[pos++] = temp[i];
     460             :     }
     461             : 
     462             :     buf[pos] = '\0';
     463             :     return pos;
     464             : }
     465             : 
     466             : int pt_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) {
     467             :     size_t pos = 0;
     468             :     const char *p = fmt;
     469             : 
     470             :     if (size == 0) return 0;
     471             : 
     472             :     while (*p && pos < size - 1) {
     473             :         if (*p != '%') {
     474             :             buf[pos++] = *p++;
     475             :             continue;
     476             :         }
     477             : 
     478             :         p++; /* Skip '%' */
     479             : 
     480             :         /* Parse flags and width */
     481             :         int zero_pad = 0;
     482             :         int width = 0;
     483             : 
     484             :         if (*p == '0') {
     485             :             zero_pad = 1;
     486             :             p++;
     487             :         }
     488             : 
     489             :         while (*p >= '0' && *p <= '9') {
     490             :             width = width * 10 + (*p - '0');
     491             :             p++;
     492             :         }
     493             : 
     494             :         /* Parse length modifier */
     495             :         int is_long = 0;
     496             :         if (*p == 'l') {
     497             :             is_long = 1;
     498             :             p++;
     499             :         }
     500             : 
     501             :         /* Parse format specifier */
     502             :         switch (*p) {
     503             :             case 'd': {
     504             :                 long val = is_long ? va_arg(args, long) : va_arg(args, int);
     505             :                 int written = pt_format_int(val, 10, width, zero_pad, 0, 1,
     506             :                                            buf + pos, size - pos);
     507             :                 pos += written;
     508             :                 break;
     509             :             }
     510             :             case 'u': {
     511             :                 unsigned long val = is_long ? va_arg(args, unsigned long)
     512             :                                             : va_arg(args, unsigned int);
     513             :                 int written = pt_format_int((long)val, 10, width, zero_pad,
     514             :                                            0, 0, buf + pos, size - pos);
     515             :                 pos += written;
     516             :                 break;
     517             :             }
     518             :             case 'x': {
     519             :                 unsigned long val = is_long ? va_arg(args, unsigned long)
     520             :                                             : va_arg(args, unsigned int);
     521             :                 int written = pt_format_int((long)val, 16, width, zero_pad,
     522             :                                            0, 0, buf + pos, size - pos);
     523             :                 pos += written;
     524             :                 break;
     525             :             }
     526             :             case 'X': {
     527             :                 unsigned long val = is_long ? va_arg(args, unsigned long)
     528             :                                             : va_arg(args, unsigned int);
     529             :                 int written = pt_format_int((long)val, 16, width, zero_pad,
     530             :                                            1, 0, buf + pos, size - pos);
     531             :                 pos += written;
     532             :                 break;
     533             :             }
     534             :             case 'p': {
     535             :                 void *ptr = va_arg(args, void *);
     536             :                 if (pos < size - 3) {
     537             :                     buf[pos++] = '0';
     538             :                     buf[pos++] = 'x';
     539             :                 }
     540             :                 int written = pt_format_int((long)ptr, 16, 8, 1, 0, 0,
     541             :                                            buf + pos, size - pos);
     542             :                 pos += written;
     543             :                 break;
     544             :             }
     545             :             case 's': {
     546             :                 const char *str = va_arg(args, const char *);
     547             :                 if (str == NULL) str = "(null)";
     548             :                 while (*str && pos < size - 1) {
     549             :                     buf[pos++] = *str++;
     550             :                 }
     551             :                 break;
     552             :             }
     553             :             case 'c': {
     554             :                 char c = (char)va_arg(args, int);
     555             :                 if (pos < size - 1) {
     556             :                     buf[pos++] = c;
     557             :                 }
     558             :                 break;
     559             :             }
     560             :             case '%': {
     561             :                 if (pos < size - 1) {
     562             :                     buf[pos++] = '%';
     563             :                 }
     564             :                 break;
     565             :             }
     566             :             default:
     567             :                 /* Unknown format - just copy it */
     568             :                 if (pos < size - 1) {
     569             :                     buf[pos++] = '%';
     570             :                 }
     571             :                 if (pos < size - 1 && *p) {
     572             :                     buf[pos++] = *p;
     573             :                 }
     574             :                 break;
     575             :         }
     576             : 
     577             :         if (*p) p++;
     578             :     }
     579             : 
     580             :     buf[pos] = '\0';
     581             :     return (int)pos;
     582             : }
     583             : 
     584             : int pt_snprintf(char *buf, size_t size, const char *fmt, ...) {
     585             :     va_list args;
     586             :     int result;
     587             :     va_start(args, fmt);
     588             :     result = pt_vsnprintf(buf, size, fmt, args);
     589             :     va_end(args);
     590             :     return result;
     591             : }
     592             : 
     593             : #endif /* PT_PLATFORM_MACTCP || PT_PLATFORM_OT */
     594             : 
     595             : /* ========================================================================== */
     596             : /* Platform-Portable Tick Getter (Phase 3)                                   */
     597             : /* ========================================================================== */
     598             : 
     599             : /*
     600             :  * Platform-portable tick getter
     601             :  *
     602             :  * Returns monotonically increasing tick count.
     603             :  * Resolution varies by platform but sufficient for coalescing/priority.
     604             :  */
     605             : #if defined(PT_PLATFORM_MACTCP) || defined(PT_PLATFORM_OT)
     606             :     /* Classic Mac - use TickCount() directly (60 ticks/sec)
     607             :      * TickCount() is declared in OSUtils.h, NOT Timer.h
     608             :      * NOTE: TickCount() is NOT documented as interrupt-safe in Inside Macintosh
     609             :      * Table B-3. Do NOT call from ASR/notifier - use timestamp=0 instead.
     610             :      */
     611             :     #include <OSUtils.h>
     612             :     uint32_t pt_get_ticks(void) {
     613             :         return (uint32_t)TickCount();
     614             :     }
     615             : #else
     616             :     /* POSIX - use milliseconds */
     617          91 :     uint32_t pt_get_ticks(void) {
     618             :         struct timespec ts;
     619          91 :         clock_gettime(CLOCK_MONOTONIC, &ts);
     620          91 :         return (uint32_t)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
     621             :     }
     622             : #endif

Generated by: LCOV version 1.14