install-exec-hook:
if BUILD_FOR_LINUX
+# NQPTP runs as user/group nqptp/nqptp on Linux and uses setcap to access ports 319 and 320
+ setcap 'cap_net_bind_service=+ep' $(bindir)/nqptp
+# no installer for System V
if INSTALL_SYSTEMD_STARTUP
+ getent group nqptp &>/dev/null || groupadd -r nqptp &>/dev/null
+ getent passwd nqptp &> /dev/null || useradd -r -M -g nqptp -s /usr/sbin/nologin nqptp &>/dev/null
[ -e $(DESTDIR)$(libdir)/systemd/system ] || mkdir -p $(DESTDIR)$(libdir)/systemd/system
# don't replace a service file if it already exists...
[ -e $(DESTDIR)$(libdir)/systemd/system/nqptp.service ] || cp nqptp.service $(DESTDIR)$(libdir)/systemd/system
endif
endif
- # no installer for FreeBSD yet
+
if BUILD_FOR_FREEBSD
+# NQPTP runs as root on FreeBSD to access ports 319 and 320
if INSTALL_FREEBSD_STARTUP
cp nqptp.freebsd /usr/local/etc/rc.d/nqptp
chmod 555 /usr/local/etc/rc.d/nqptp
i++;
}
if (response != -1) {
- pthread_mutexattr_t shared;
- int err;
strncpy(clients[i].shm_interface_name, client_shared_memory_interface_name,
sizeof(clients[i].shm_interface_name));
// create the named smi interface
memset(clients[i].shared_memory, 0, sizeof(struct shm_structure));
clients[i].shared_memory->version = NQPTP_SHM_STRUCTURES_VERSION;
- /*create mutex attr */
- err = pthread_mutexattr_init(&shared);
- if (err != 0) {
- die("mutex attribute initialization failed - %s.", strerror(errno));
- }
- pthread_mutexattr_setpshared(&shared, 1);
- /*create a mutex */
- err = pthread_mutex_init((pthread_mutex_t *)&clients[i].shared_memory->shm_mutex, &shared);
- if (err != 0) {
- die("mutex initialization failed - %s.", strerror(errno));
- }
-
- err = pthread_mutexattr_destroy(&shared);
- if (err != 0) {
- die("mutex attribute destruction failed - %s.", strerror(errno));
- }
-
// for (i = 0; i < MAX_CLOCKS; i++) {
// clocks_private[i].client_flags[response] =
// 0; // turn off all client flags in every clock for this client
void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time,
uint64_t local_to_master_offset, uint64_t mastership_start_time) {
- // debug(1,"update_master_clock_info clock: % " PRIx64 ", offset: %" PRIx64 ".",
- // master_clock_id, local_to_master_offset);
- int rc = pthread_mutex_lock(&shared_memory->shm_mutex);
- if (rc != 0)
- warn("Can't acquire mutex to update master clock!");
- shared_memory->master_clock_id = master_clock_id;
+ // to ensure that a full update has taken place, the
+ // reader must ensure that the main and secondary
+ // structures are identical
+
+ shared_memory->main.master_clock_id = master_clock_id;
if (ip != NULL) {
- strncpy((char *)&shared_memory->master_clock_ip, ip,
- FIELD_SIZEOF(struct shm_structure, master_clock_ip) - 1);
- shared_memory->master_clock_start_time = mastership_start_time;
- shared_memory->local_time = local_time;
- shared_memory->local_to_master_time_offset = local_to_master_offset;
+ shared_memory->main.master_clock_start_time = mastership_start_time;
+ shared_memory->main.local_time = local_time;
+ shared_memory->main.local_to_master_time_offset = local_to_master_offset;
} else {
- shared_memory->master_clock_ip[0] = '\0';
- shared_memory->master_clock_start_time = 0;
- shared_memory->local_time = 0;
- shared_memory->local_to_master_time_offset = 0;
+ shared_memory->main.master_clock_start_time = 0;
+ shared_memory->main.local_time = 0;
+ shared_memory->main.local_to_master_time_offset = 0;
}
- rc = pthread_mutex_unlock(&shared_memory->shm_mutex);
- if (rc != 0)
- warn("Can't release mutex after updating master clock!");
- // debug(1,"update_master_clock_info done");
+ __sync_synchronize();
+ shared_memory->secondary = shared_memory->main;
+ __sync_synchronize();
}
/*
* This file is part of the nqptp distribution (https://github.com/mikebrady/nqptp).
- * Copyright (c) 2021--2022 Mike Brady.
+ * Copyright (c) 2021--2023 Mike Brady.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#define NQPTP_INTERFACE_NAME "/nqptp"
-#define NQPTP_SHM_STRUCTURES_VERSION 9
+#define NQPTP_SHM_STRUCTURES_VERSION 10
#define NQPTP_CONTROL_PORT 9000
// The control port expects a UDP packet with the first character being a command letter
// When the clock is inactive, it can stop running. This causes the offset to decrease.
// NQPTP clock smoothing would treat this as a network delay, causing true sync to be lost.
// To avoid this, when the clock goes from inactive to active,
-// NQPTP resets clock smoothing to the new offset.
-
+// NQPTP resets clock smoothing to the new offset.
#include <inttypes.h>
#include <pthread.h>
-struct shm_structure {
- pthread_mutex_t shm_mutex; // for safely accessing the structure
- uint16_t version; // check this is equal to NQPTP_SHM_STRUCTURES_VERSION
+typedef struct {
uint64_t master_clock_id; // the current master clock
- char master_clock_ip[64]; // where it's coming from
uint64_t local_time; // the time when the offset was calculated
uint64_t local_to_master_time_offset; // add this to the local time to get master clock time
uint64_t master_clock_start_time; // this is when the master clock became master
+} shm_structure_set;
+
+// The actual interface comprises a shared memory region of type struct shm_structure.
+// This comprises two records of type shm_structure_set.
+// The secondary record is written strictly after all writes to the main record are
+// complete. This is ensured using the __sync_synchronize() construct.
+// The reader should ensure that both copies match for a read to be valid.
+// For safety, the secondary record should be read strictly after the first.
+
+struct shm_structure {
+ uint16_t version; // check this is equal to NQPTP_SHM_STRUCTURES_VERSION
+ shm_structure_set main;
+ shm_structure_set secondary;
};
#endif
#endif
#ifdef CONFIG_FOR_FREEBSD
-#include <sys/types.h>
-#include <unistd.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
#endif
#include <netdb.h> // getaddrinfo etc.
// close off new smi
// mmap cleanup
if (munmap(shared_memory, sizeof(struct shm_structure)) != 0) {
- debug(1, "error unmapping shared memory \"%s\": \"%s\".", NQPTP_INTERFACE_NAME, strerror(errno));
+ debug(1, "error unmapping shared memory \"%s\": \"%s\".", NQPTP_INTERFACE_NAME,
+ strerror(errno));
}
// shm_open cleanup
if (shm_unlink(NQPTP_INTERFACE_NAME) == -1) {
- debug(1, "error unlinking shared memory \"%s\": \"%s\".", NQPTP_INTERFACE_NAME, strerror(errno));
+ debug(1, "error unlinking shared memory \"%s\": \"%s\".", NQPTP_INTERFACE_NAME,
+ strerror(errno));
}
if (shm_fd != -1)
if (strcmp(argv[i] + 1, "V") == 0) {
#ifdef CONFIG_USE_GIT_VERSION_STRING
if (git_version_string[0] != '\0')
- fprintf(stdout, "Version: %s. Shared Memory Interface Version: smi%u.\n", git_version_string,
- NQPTP_SHM_STRUCTURES_VERSION);
+ fprintf(stdout, "Version: %s. Shared Memory Interface Version: smi%u.\n",
+ git_version_string, NQPTP_SHM_STRUCTURES_VERSION);
else
#endif
// open the SMI
- pthread_mutexattr_t shared;
- int err;
-
shm_fd = -1;
mode_t oldumask = umask(0);
- shm_fd = shm_open(NQPTP_INTERFACE_NAME, O_RDWR | O_CREAT, 0666);
+ shm_fd = shm_open(NQPTP_INTERFACE_NAME, O_RDWR | O_CREAT, 0644);
if (shm_fd == -1) {
die("cannot open shared memory \"%s\".", NQPTP_INTERFACE_NAME);
}
memset(shared_memory, 0, sizeof(struct shm_structure));
shared_memory->version = NQPTP_SHM_STRUCTURES_VERSION;
- /*create mutex attr */
- err = pthread_mutexattr_init(&shared);
- if (err != 0) {
- die("mutex attribute initialization failed - %s.", strerror(errno));
- }
- pthread_mutexattr_setpshared(&shared, 1);
- /*create a mutex */
- err = pthread_mutex_init((pthread_mutex_t *)&shared_memory->shm_mutex, &shared);
- if (err != 0) {
- die("mutex initialization failed - %s.", strerror(errno));
- }
-
- err = pthread_mutexattr_destroy(&shared);
- if (err != 0) {
- die("mutex attribute destruction failed - %s.", strerror(errno));
- }
-
ssize_t recv_len;
char buf[BUFLEN];
[Service]
ExecStart=@prefix@/bin/nqptp
-User=root
-Group=root
+User=nqptp
+Group=nqptp
[Install]
WantedBy=multi-user.target