From b3b7abaf7bd9c0dc0138f651fc534e1671b99254 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 11 Jul 2024 00:48:49 -0500 Subject: [PATCH] Progress: Continue migrating the project, updating documentation and fixing some bugs. Update the specifications and documentation. Drop the "/var" default in "/var/run" to just be "/run". This is nice and newer systems are following this. The process flags should actually be on a flag variable inside the process structure. This flag variable got lost in migration and is now back. Provide additional lock structural changes. Make stronger attempts to re-establish the read locks. (There will likely be more updates to follow regarding F_lock_read and F_lock_write.) The need to release a read lock to get a write lock within the same thread is unideal. I do not like how this is. It has probably annoyed me in the past and it annoys me yet again. The POSIX thread documentation man pages are quite lacking in some critical information in this area. I will have to do a lot of research. Maybe at some point in the future I might depend on a different threading system that is more sane. I accidentally had the instance action lock being locked when the regular instance lock should be grabbed. This caused the utility execution (or anything that executes based on a PID file) to just sit there after the first run. This is a migration mistake that is now fixed. I did notice that on PID file error this thread still does not exit but the 0.6 version does exit. This is likely another migration bug that needs to be fixed. Or this is a problem resulting from adding the F_lock_read and F_lock_write return values without getting the time to go and have the callers expect this return result. Add some new functions for returning a pointer so that I can make the pointer a constant in the execute functions. --- documents/entry.txt | 6 +- documents/exit.txt | 6 +- documents/readme.bootstrap.txt | 138 -------------- documents/readme.build.txt | 351 ++++++++++++++++++++++++++++------- documents/readme.txt | 59 ++---- documents/time.txt | 52 ------ sources/c/init/string.h | 8 +- sources/c/main/common/type/process.h | 3 + sources/c/main/entry/process.c | 8 +- sources/c/main/instance/prepare.c | 8 +- sources/c/main/instance/prepare.h | 2 +- sources/c/main/lock.c | 30 +-- sources/c/main/lock.h | 74 ++------ sources/c/main/perform.c | 2 +- sources/c/main/rule/execute.c | 203 +++++++++----------- sources/c/main/rule/execute.h | 68 ++++++- sources/c/main/rule/instance.c | 4 +- sources/c/main/rule/wait.c | 16 +- sources/c/main/thread/entry.c | 4 +- specifications/time.txt | 156 ---------------- 20 files changed, 495 insertions(+), 703 deletions(-) delete mode 100644 documents/readme.bootstrap.txt delete mode 100644 documents/time.txt delete mode 100644 specifications/time.txt diff --git a/documents/entry.txt b/documents/entry.txt index aee41ea..5292125 100644 --- a/documents/entry.txt +++ b/documents/entry.txt @@ -1,7 +1,7 @@ # fss-0002 iki-0000 # # license: open-standard-license-1.0-or-later -# version 2024/07/02 +# version 2024/07/10 # # This file (assumed to be named entry.txt) can be more easily read using the following iki_read commands: # iki_read entry.txt +Q -r PID PID -w -WW code '"' '"' @@ -173,8 +173,8 @@ Entry Documentation: - The code:"ready" Item Action\: Instructs the controller program when it is safe to perform normal tasks, such as creating the PID:"Process Identifier" file. When not specified, the state is always assumed to be ready. - For example, the controller program may be used as a full blown code:"init" replacement and therefore may need to mount the /var/run/ directory. - If the PID:"Process Identifier" file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready. + For example, the controller program may be used as a full blown code:"init" replacement and therefore may need to mount the /run/ directory. + If the PID:"Process Identifier" file is created at program start, then the /run/controller.pid would be written before the /run/ directory is ready. This could be a problem, such as on a read-only file system the PID:"Process Identifier" creation fails and controller bails out on error. Adding code:"ready" essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations. When the optional code:"wait" is provided, then code:"ready" will wait for all currently started asynchronous processes to complete before operating. diff --git a/documents/exit.txt b/documents/exit.txt index d6bce76..499991f 100644 --- a/documents/exit.txt +++ b/documents/exit.txt @@ -1,7 +1,7 @@ # fss-0002 iki-0000 # # license: open-standard-license-1.0-or-later -# version 2024/07/02 +# version 2024/07/10 # # This file (assumed to be named exit.txt) can be more easily read using the following iki_read commands: # iki_read exit.txt +Q -w -r PID PID -w -W code '"' '"' @@ -117,8 +117,8 @@ Exit Documentation: - The code:"ready" Action\: Instructs the controller program when it is safe to perform normal tasks, such as creating the PID:"Process Identifier" file. When not specified, the state is always assumed to be ready. - For example, the controller program may be used as a full blown code:"init" replacement and therefore may need to mount the /var/run/ directory. - If the PID:"Process Identifier" file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready. + For example, the controller program may be used as a full blown code:"init" replacement and therefore may need to mount the /run/ directory. + If the PID:"Process Identifier" file is created at program start, then the /run/controller.pid would be written before the /run/ directory is ready. This could be a problem, such as on a read-only file system the PID:"Process Identifier" creation fails and controller bails out on error. Adding code:"ready" essentially specifies a point in time in the Exit in which things are expected to be safe for such basic operations. When the optional code:"wait" is provided, then code:"ready" will wait for all currently started asynchronous processes to complete before operating. diff --git a/documents/readme.bootstrap.txt b/documents/readme.bootstrap.txt deleted file mode 100644 index bfc7512..0000000 --- a/documents/readme.bootstrap.txt +++ /dev/null @@ -1,138 +0,0 @@ -# fss-0002 iki-0000 -# -# license: cc-by-sa-4.0 -# version 2024/07/02 -# -# This file (assumed to be named readme.bootstrap.txt) can be more easily read using the following iki_read commands: -# iki_read readme.bootstrap.txt +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"' -# -# To read the "Bootstrap Readme Documentation" section of this file, use this command sequence: -# fss_basic_list_read readme.bootstrap.txt +Q -cn "Bootstrap Readme Documentation" | iki_read +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"' -# - -Bootstrap Readme Documentation: - The FLL:"Featureless Linux Library" provides a special bootstrap script in case the bold:"Featureless Make" is not currently installed. - - The bold:"GNU Bash" scripts, called file:"bootstrap.sh" and file:"install.sh", are provided to perform this bootstrap process. - - The syntax for file:"bootstrap.sh" is\: - code:"bootstrap.sh [options]" - - where operation is one of the following: code:"build" or code:"clean". - - No code:"install" command is provided, all of the files to install may be found in the file:"build/" directory after the build command is executed. - - To install, either copy the files in the build directory to their appropriate destination or use the file:"install.sh" bold:"GNU Bash" script. - - For all operations and options, get help from the bootstrap script by appending the code:"--help" to the script, such as: code:"./bootstrap.sh --help". - - The monolithic build process is the simplest, which can be generated like the following: code:"./bootstrap.sh build -m monolithic". - - When during development, consider using a work directory, such as: code:"./bootstrap.sh --work /tmp/work". - - The syntax for file:"install.sh" is\: - code:"install.sh [options]" - - This defaults to code:"/usr/local/" paths commonly found in bold:"GNU Linux" systems. - - Accepts options for specifying specific install directory paths, such as a custom bin directory: code:"./install.sh --bindir /custom/program". - - This is a simple installer and is not intended to be an all-solution. - - For more powerful installation: manually install, use custom scripts, or use an appropriate build/install system. - - When during development, consider using a work directory, such as: code:"./install.sh --work /tmp/work". - - The code:"--work" parameter in file:"install.sh" is similar to the code:"--prefix" parameter, except that it is used for easier development scripting and also for communicating intent and has a different directory structure. - - The bold:"Featureless Make" is a build system only and not an install system, the file:"install.sh" script may still be needed to install when using the bold:"Featureless Make". - - Build Example\: - code:"./bootstrap.sh build" - - Install Example\: - code:"./install.sh" - - Manual Install Example\: - code:"cp -vR build/includes/* /usr/include/" - code:"cp -vR build/libaries/shared/* /usr/lib/" - code:"cp -vR build/programs/shared/* /usr/bin/" - code:"cp -vR build/settings/* /etc/" - - If one of the build sub-directories, such as includes, libraries, programs, and settings, is empty or missing after a successful build, then there are no files of that type to install. - - Build Tree Structure Example (using the FLL:"Featureless Linux Library" code:"status_code-0.7.0" project)\: - block:" - build/ - ├── documents - ├── includes - │   └── program - │   └── status_code - │   ├── fss - │   │   ├── common.h - │   │   └── status_code.h - │   └── main - │   ├── common.h - │   ├── common-print.h - │   ├── print.h - │   └── status_code.h - ├── libraries - │   ├── script - │   ├── shared - │   │   ├── libstatus_code.so -> libstatus_code.so.0 - │   │   ├── libstatus_code.so.0 -> libstatus_code.so.0.7 - │   │   ├── libstatus_code.so.0.7 -> libstatus_code.so.0.7.0 - │   │   └── libstatus_code.so.0.7.0 - │   └── static - │   └── libstatus_code.a - ├── objects - │   ├── config.o - │   ├── fss - │   │   ├── common.o - │   │   └── status_code.o - │   ├── main - │   │   ├── common.o - │   │   ├── common-print.o - │   │   ├── print.o - │   │   ├── private-status_code.o - │   │   └── status_code.o - │   ├── script - │   ├── shared - │   └── static - ├── programs - │   ├── script - │   ├── shared - │   │   ├── fss_status_code - │   │   └── status_code - │   └── static - │   ├── fss_status_code - │   └── status_code - ├── settings - └── stage - ├── library_shared-settings.built - ├── library_static-settings.built - ├── objects_static-settings.built - ├── program_shared-settings.fss.built - ├── program_shared-settings.main.built - ├── skeleton-settings.built - ├── skeleton-settings.fss.built - ├── skeleton-settings.main.built - ├── sources_headers-settings.built - ├── sources_script-settings.built - ├── sources_script-settings.fss.built - ├── sources_script-settings.main.built - ├── sources_settings-settings.built - ├── sources_settings-settings.fss.built - └── sources_settings-settings.main.built - " - - Work Tree Sructure Example at file:"/tmp/work" (using the FLL:"Featureless Linux Library" code:"status_code-0.7.0" project)\: - block:" - /tmp/work/ - ├── includes - │   └── program - │   └── status_code - │   ├── fss - │   │   ├── common.h - │   │   └── status_code.h - │   └── main - │   ├── common.h - │   ├── common-print.h - │   ├── print.h - │   └── status_code.h - └── libraries - ├── shared - │   ├── libstatus_code.so -> libstatus_code.so.0 - │   ├── libstatus_code.so.0 -> libstatus_code.so.0.7 - │   ├── libstatus_code.so.0.7 -> libstatus_code.so.0.7.0 - │   └── libstatus_code.so.0.7.0 - └── static - └── libstatus_code.a - " diff --git a/documents/readme.build.txt b/documents/readme.build.txt index 678e0a3..db613c4 100644 --- a/documents/readme.build.txt +++ b/documents/readme.build.txt @@ -1,7 +1,7 @@ # fss-0002 iki-0000 # # license: cc-by-sa-4.0 -# version 2024/07/02 +# version 2024/07/10 # # This file (assumed to be named readme.build.txt) can be more easily read using the following iki_read commands: # iki_read readme.build.txt +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"' @@ -12,99 +12,324 @@ Build Readme Documentation: The bold:"Featureless Make", or code:"fake", is a build system opposing the bold:"GNU Make" build (and install) system. + See the code:"fake" project for further details regarding that build system. - The bold:"GNU Make" system is powerful, but introduces too much unecessary functionality. - In opposition to parts of how bold:"GNU Make" works but also in honor of the success of the bold:"GNU Make" system, the bold:"Featureless Make" system follows the following concepts\: - - A build system is just that, a build system. Do not attempt to install, leave that to the distributor or individual installer. - - A build system should not be trying to guess what is or is not on the system, instead, allow the distributor or individual installer to just specify what they want. - - Provide a simple configuration design by using the bold:"Featureless Settings Specification". - - Provide advanced functionality to provide flexibility with different system designs. - - Userspace execution calling is expensive, attempt to avoid such overhead by providing built-in functionality where reasonably possible. - - There should never need to be a code:"configure" script, like bold:"GNU Autoconf". - - The code:"fake" is designed to specifically build the FLL:"Featureless Linux Library" and encourages the use of code:"fake" to build FLL:"Featureless Linux Library". - - The code:"fake" provides two main build operations\: - - code:"build": a lean purely FSS:"Featureless Settings Specification" based build process, designed around specific but simple project designs (explicitly used by FLL:"Featureless Linux Library"). - - code:"make": a more powerful build process design to be more akin to bold:"GNU Make". + Use the code:"make" operation from the code:"fake" program to build this project\: + code:"fake" - The code:"fake" supports custom development environments using the file:"work" directory concept, such as code:"fake build -w /tmp/work". - The file:"work" directory structure is identical to the build directory structure. + If the project has already been built before, alternative consider performing both a code:"clean" and an explicit code:"make" operation\: + code:"fake clean make" - Build Example, Using code:"build"\: - code:"fake build" + After building, either run the helper file:"install.sh" script or manually install the build files. - Build Example, Using code:"make"\: - code:"fake" + Install Example\: + code:"./install.sh" - Build Example, Explicitly Using code:"make"\: - code:"fake make" + Manual Install Example\: + code:"cp -vR build/documentation/* /usr/share/" + code:"cp -vR build/includes/* /usr/include/" + code:"cp -vR build/libaries/shared/* /usr/lib/" + code:"cp -vR build/programs/shared/* /usr/bin/" + code:"cp -vR build/settings/* /etc/" - Build Tree Structure Example (using the FLL:"Featureless Linux Library" code:"status_code-0.7.0" project)\: + Build Tree Structure Example (using an early code:"controller-0.7.0" project structure)\: block:" build/ + ├── documentation + │   └── man + │   ├── man1 + │   │   └── controller.1 + │   └── man5 + │   ├── controller-actions.5 + │   ├── controller-entry.5 + │   ├── controller-exit.5 + │   ├── controller-packet.5 + │   └── controller-rule.5 ├── documents ├── includes │   └── program - │   └── status_code - │   ├── fss - │   │   ├── common.h - │   │   └── status_code.h + │   └── controller + │   ├── controller + │   │   ├── controller.h + │   │   └── string.h + │   ├── init + │   │   ├── init.h + │   │   └── string.h │   └── main + │   ├── common + │   │   ├── define + │   │   │   ├── control.h + │   │   │   ├── entry.h + │   │   │   ├── rule.h + │   │   │   └── thread.h + │   │   ├── define.h + │   │   ├── enumeration + │   │   │   ├── control.h + │   │   │   ├── entry.h + │   │   │   ├── instance.h + │   │   │   ├── process.h + │   │   │   ├── rule.h + │   │   │   └── thread.h + │   │   ├── enumeration.h + │   │   ├── print.h + │   │   ├── string + │   │   │   ├── general.h + │   │   │   └── rule.h + │   │   ├── string.h + │   │   ├── type + │   │   │   ├── cache.h + │   │   │   ├── control.h + │   │   │   ├── defs.h + │   │   │   ├── entry.h + │   │   │   ├── execute.h + │   │   │   ├── instance.h + │   │   │   ├── interrupt.h + │   │   │   ├── lock.h + │   │   │   ├── process.h + │   │   │   ├── rule.h + │   │   │   └── thread.h + │   │   └── type.h │   ├── common.h - │   ├── common-print.h - │   ├── print.h - │   └── status_code.h + │   ├── controller.h + │   ├── convert.h + │   ├── entry + │   │   ├── action.h + │   │   ├── preprocess.h + │   │   ├── process.h + │   │   └── setting.h + │   ├── entry.h + │   ├── file.h + │   ├── instance + │   │   ├── prepare.h + │   │   └── wait.h + │   ├── instance.h + │   ├── lock.h + │   ├── path.h + │   ├── perform.h + │   ├── print + │   │   ├── data.h + │   │   ├── debug + │   │   │   ├── perform + │   │   │   │   ├── control.h + │   │   │   │   └── pid.h + │   │   │   └── rule + │   │   │   ├── action.h + │   │   │   └── execute.h + │   │   ├── debug.h + │   │   ├── error + │   │   │   ├── entry + │   │   │   │   ├── action.h + │   │   │   │   ├── item.h + │   │   │   │   └── setting.h + │   │   │   ├── entry.h + │   │   │   ├── lock.h + │   │   │   ├── perform + │   │   │   │   └── pid.h + │   │   │   ├── rule + │   │   │   │   ├── action.h + │   │   │   │   ├── item.h + │   │   │   │   └── setting.h + │   │   │   └── rule.h + │   │   ├── error.h + │   │   ├── lock.h + │   │   ├── message + │   │   │   ├── entry + │   │   │   │   ├── action.h + │   │   │   │   └── item.h + │   │   │   └── entry.h + │   │   ├── message.h + │   │   ├── output + │   │   │   ├── entry + │   │   │   │   └── setting.h + │   │   │   └── rule + │   │   │   ├── execute.h + │   │   │   ├── setting.h + │   │   │   └── validate.h + │   │   ├── verbose.h + │   │   ├── warning + │   │   │   ├── entry + │   │   │   │   ├── action.h + │   │   │   │   ├── item.h + │   │   │   │   └── setting.h + │   │   │   └── rule + │   │   │   ├── action.h + │   │   │   ├── item.h + │   │   │   └── setting.h + │   │   └── warning.h + │   ├── process.h + │   ├── rule + │   │   ├── action.h + │   │   ├── execute.h + │   │   ├── expand.h + │   │   ├── instance.h + │   │   ├── is.h + │   │   ├── item.h + │   │   ├── parameter.h + │   │   ├── read.h + │   │   ├── setting.h + │   │   └── wait.h + │   ├── rule.h + │   ├── signal.h + │   ├── status.h + │   ├── thread + │   │   ├── cleanup.h + │   │   ├── control.h + │   │   ├── entry.h + │   │   ├── instance.h + │   │   ├── is.h + │   │   ├── rule.h + │   │   └── signal.h + │   ├── thread.h + │   ├── time.h + │   └── validate.h ├── libraries │   ├── script │   ├── shared - │   │   ├── libstatus_code.so -> libstatus_code.so.0 - │   │   ├── libstatus_code.so.0 -> libstatus_code.so.0.7 - │   │   ├── libstatus_code.so.0.7 -> libstatus_code.so.0.7.0 - │   │   └── libstatus_code.so.0.7.0 + │   │   ├── libcontroller.so -> libcontroller.so.0 + │   │   ├── libcontroller.so.0 -> libcontroller.so.0.7 + │   │   ├── libcontroller.so.0.7 -> libcontroller.so.0.7.0 + │   │   └── libcontroller.so.0.7.0 │   └── static - │   └── libstatus_code.a ├── objects - │   ├── config.o - │   ├── fss - │   │   ├── common.o - │   │   └── status_code.o - │   ├── main - │   │   ├── common.o - │   │   ├── common-print.o - │   │   ├── print.o - │   │   ├── private-status_code.o - │   │   └── status_code.o │   ├── script │   ├── shared │   └── static ├── programs │   ├── script │   ├── shared - │   │   ├── fss_status_code - │   │   └── status_code + │   │   ├── controller + │   │   └── init │   └── static - │   ├── fss_status_code - │   └── status_code ├── settings + │   └── controller + │   ├── entries + │   │   ├── default.entry + │   │   └── maintenance.entry + │   ├── example + │   │   ├── cgroup_example + │   │   │   ├── entries + │   │   │   │   ├── chromium.entry + │   │   │   │   ├── eclipse.entry + │   │   │   │   ├── firefox.entry + │   │   │   │   └── setup_cgroups.entry + │   │   │   └── rules + │   │   │   ├── program + │   │   │   │   ├── chromium.rule + │   │   │   │   ├── eclipse.rule + │   │   │   │   └── firefox.rule + │   │   │   └── setup + │   │   │   └── cgroups.rule + │   │   ├── entries + │   │   │   ├── asynchronous.entry + │   │   │   ├── asynchronous-serial.entry + │   │   │   ├── delay-program.entry + │   │   │   ├── delay-service.entry + │   │   │   ├── environment.entry + │   │   │   ├── htop-alternate.entry + │   │   │   ├── htop-command.entry + │   │   │   ├── htop.entry + │   │   │   ├── iki.entry + │   │   │   ├── serial-alternate.entry + │   │   │   ├── serial.entry + │   │   │   ├── sshd.entry + │   │   │   ├── test.entry + │   │   │   ├── up.entry + │   │   │   └── utility.entry + │   │   ├── exits + │   │   │   ├── htop-alternate.exit + │   │   │   ├── serial.exit + │   │   │   └── sshd.exit + │   │   └── rules + │   │   ├── asynchronous + │   │   │   ├── sleep_10.rule + │   │   │   ├── sleep_1.rule + │   │   │   ├── sleep_2.rule + │   │   │   ├── sleep_3.rule + │   │   │   ├── sleep_5.rule + │   │   │   └── sleep_8.rule + │   │   ├── command + │   │   │   ├── htop.rule + │   │   │   └── multiple.rule + │   │   ├── delay + │   │   │   ├── long.rule + │   │   │   └── short.rule + │   │   ├── environment + │   │   │   ├── default.rule + │   │   │   ├── empty.rule + │   │   │   ├── exported.rule + │   │   │   ├── exporting.rule + │   │   │   ├── fake-nothing.rule + │   │   │   └── fake-something.rule + │   │   ├── maintenance + │   │   │   └── boom.rule + │   │   ├── print + │   │   │   └── newline.rule + │   │   ├── script + │   │   │   ├── create_socket_path.rule + │   │   │   ├── fail.rule + │   │   │   ├── iki.rule + │   │   │   ├── php.rule + │   │   │   ├── python.rule + │   │   │   ├── require_me.rule + │   │   │   └── succeed.rule + │   │   ├── serial + │   │   │   ├── s_1.rule + │   │   │   ├── s_2.rule + │   │   │   ├── s_3.rule + │   │   │   ├── s_4.rule + │   │   │   ├── s_5.rule + │   │   │   └── s_6.rule + │   │   ├── service + │   │   │   └── sshd.rule + │   │   └── utility + │   │   ├── sleeper_1.rule + │   │   ├── sleeper_2.rule + │   │   └── sleeper_3.rule + │   └── rules + │   ├── boot + │   │   ├── devices.rule + │   │   ├── file_system.rule + │   │   ├── modules.rule + │   │   ├── proc.rule + │   │   └── root.rule + │   ├── maintenance + │   │   └── console.rule + │   ├── net + │   │   ├── all.rule + │   │   └── loopback.rule + │   ├── service + │   │   ├── dbus.rule + │   │   ├── logger.rule + │   │   └── mouse.rule + │   ├── task + │   │   ├── clock.rule + │   │   ├── keyboard.rule + │   │   └── ntpdate.rule + │   └── terminal + │   ├── four.rule + │   ├── one.rule + │   ├── three.rule + │   └── two.rule └── stage ├── library_shared-settings.built - ├── library_static-settings.built - ├── objects_static-settings.built - ├── program_shared-settings.fss.built - ├── program_shared-settings.main.built + ├── program_shared-settings.controller.built + ├── program_shared-settings.init.built ├── skeleton-settings.built - ├── skeleton-settings.fss.built - ├── skeleton-settings.main.built + ├── skeleton-settings.controller.built + ├── skeleton-settings.init.built + ├── sources_documentation-settings.built + ├── sources_documentation-settings.controller.built + ├── sources_documentation-settings.init.built ├── sources_headers-settings.built + ├── sources_headers-settings.controller.built + ├── sources_headers-settings.init.built ├── sources_script-settings.built - ├── sources_script-settings.fss.built - ├── sources_script-settings.main.built + ├── sources_script-settings.controller.built + ├── sources_script-settings.init.built ├── sources_settings-settings.built - ├── sources_settings-settings.fss.built - └── sources_settings-settings.main.built + ├── sources_settings-settings.controller.built + └── sources_settings-settings.init.built " - See: FLL:"Featureless Linux Library" code:"fake" project documents for further details on how to use the bold:"Featureless Make" system. - See: FLL:"Featureless Linux Library" code:"fake" project specifications for how to configure the build FSS:"Featureless Settings Specification" files and make FSS:"Featureless Settings Specification" files. - See: file:"readme.bootstrap.txt" for notes on installing. + See: FLL:"Featureless Linux Library" code:"fake" project documents and specifications for further details on how to use the bold:"Featureless Make" system. + See: FLL:"Featureless Linux Library" project documentation and specifications for how to configure the bold:"Featureless Make" FSS:"Featureless Settings Specification" files. diff --git a/documents/readme.txt b/documents/readme.txt index 01423f0..4dfd468 100644 --- a/documents/readme.txt +++ b/documents/readme.txt @@ -1,63 +1,30 @@ # fss-0002 iki-0000 # # license: cc-by-sa-4.0 -# version 2024/07/02 +# version 2024/07/10 # # This file (assumed to be named readme.build.txt) can be more easily read using the following iki_read commands: -# iki_read readme.txt +Q -w -rrrr API API FLL FLL FSS FSS KISS KISS -WW character "'" "'" code '"' '"' +# iki_read readme.txt +Q -w -r FLL FLL # # To read the "Readme Documentation" section of this file, use this command sequence: -# fss_basic_list_read readme.txt +Q -cn "Readme Documentation" | iki_read +Q -w -rrrr API API FLL FLL FSS FSS KISS KISS -WW character "'" "'" code '"' '"' +# fss_basic_list_read readme.txt +Q -cn "Readme Documentation" | iki_read +Q -w -r FLL FLL # Readme Documentation: - The FLL:"Featureless Linux Library" is a set of projects designed to be used for bold:"Linux" programming. + The Controller program utilizes the FLL:"Featureless Linux Library" and is designed to be used for bold:"Linux" systems. - The FLL:"Featureless Linux Library" is design around the following concepts\: - - API:"Application Programming Interface" designed around communicating to the programmer and maintaining unchanging consistency. - - Hacker friendly, promote changing the project via its designed methodologies, implementations, standards, practices, and licenses. - - Add freedom back to computing, via the bold:"LGPL" license, because a library is a library. - - A standard is not a true standard if it is not freely available and cannot be freely used or followed. - - Avoid the bold:"feature" trap where projects keep adding things. - - Provide an explicit versioning system that is more than a number, it communicates the status in a very simple manner. - - Continue mantaining major versions, a project should be able to last 20, 30, or even 60 years without breaking changes. - - Follow the KISS:"Keep It Simple Stupid", principles. - - Can be broken up into individual projects, and then further fine-tuned via custom define macros, so that only what is needed for specific situations need be used. + This project follows many of the FLL:"Featureless Linux Library" project practices and the documentation provided by that project should be consulted for further details in this regard. - The FLL:"Featureless Linux Library" versioning system has three parts: code:"major.minor.micro". - - The bold:"Major" is the primary API:"Application Programming Interface" specification, changes to this number represent massive breaking changes and for all intents and purposes is a different project. - - The bold:"Minor" represents potential breaking changes, where odd numbers represent bold:"development status" and even numbers represent bold:"stable status". - - The bold:"Micro" represents bug fixes and security fixes, these should never introduce neither API:"Application Programming Interface" breaking changes nor new functionality. + The purpose of this project is to provide a tool to help facilitate controlled execution of processes. + This behavior is strongly correlated with how a basic system initializer works, alsa called an bold:"init" program. + An bold:"init" program is therefore provided as another alternative to the different bold:"init" programs out there. - Development releases (as specified by bold:"Minor" version part) may introduce breaking changes and new functionality. - Stable releases (as specified by the bold:"Minor" version part) may not introduce breaking change, unless forced by some security or other difficult situation, and must not add new functionality. - - The FLL:"Featureless Linux Library" project is broken up into 3 different levels: code:"level_0", code:"level_1", and code:"level_2". - A third pseudo-level also exists for common programs built using this project, called code:"level_3". - - With an exception of a few projects within code:"level_0", each level should only depend on a project from a lower level. - Therefore, a code:"level_1" project can only depend on code:"level_0" projects and a code:"level_2" project can depend on only code:"level_0" and code:"level_1" projects. - This does not technically apply to the pseudo-level, code:"level_3", projects, but the pattern is generally followed. - - A few projects in code:"level_0" are essentially required by everything and are depended on by virtually all projects, regardless of the level. - These code:"level_0" projects are\: - - code:"f_type": Provides core type definitions, code:"#define", and similar structures for the entire set of FLL:"Featureless Linux Library" projects. - - code:"f_status": provides status codes and other status codes to be used by the entire set of FLL:"Featureless Linux Library" projects. - - code:"f_memory": provides common memory allocation or deallocation to be used by the entire set of FLL:"Featureless Linux Library" projects. - - code:"f_type_array": provides an extension on code:"f_type" that requires linking to code:"f_memory" to be used by the entire set of FLL:"Featureless Linux Library" projects. - - code:"f_string": provides common string management to be used by the entire set of the FLL:"Featureless Linux Library" projects. - - code:"f_utf": provides common UTF-8 related string management to be used by the entire set of the FLL:"Featureless Linux Library" projects. - - The above projects should be installed first, and in the provided order (code:"f_type", then code:"f_status", then code:"f_memory", then code:"f_type_array", then code:"f_string", and finally code:"f_utf"). - No other code:"level_0" project should depend on another and can be installed in any order. + This project follows bold:"Specification Driven Development" and details of the configuration files are defined in the directory:"specifications/" and in the directory:"documents/". To facilitate building of this project, two different build systems are provided\: - The bootstrap, via the file:"bootstrap.sh" script. - - The bold:"Featureless Make", which is a level_3 project provided by FLL:"Featureless Linux Library". - - An example bootstrap script is provided (file:"build/scripts/bootstrap-example.sh") is provided for to show how to build the FLL:"Featureless Linux Library" directly from source. - Use it as an example or explicitly call it (such as: code:"bash build/scripts/bootstrap-example.sh monolithic 0.7.0"). + - The bold:"Featureless Make", which is a level 3 project provided by FLL:"Featureless Linux Library". - See: file:"dependencies" for specific dependencies of this project. - See: file:"readme.bootstrap.txt" for bootstrap compiling (or just regular compiling) any part of the FLL:"Featureless Linux Library" and notes on installing. - See: file:"readme.build.txt" for bold:"Featureless Make" compiling and notes on installing. + See: file:"data/build/dependencies" for specific dependencies of this project. + See: file:"documents/readme.bootstrap.txt" for bootstrap compiling (or just regular compiling) any part of the FLL:"Featureless Linux Library" and notes on installing. + See: file:"documents/readme.build.txt" for bold:"Featureless Make" compiling and notes on installing. diff --git a/documents/time.txt b/documents/time.txt deleted file mode 100644 index fcfbee5..0000000 --- a/documents/time.txt +++ /dev/null @@ -1,52 +0,0 @@ -# fss-0002 iki-0000 -# -# license: cc-by-sa-4.0 -# version 2024/07/02 -# -# This file (assumed to be named time.txt) can be more easily read using the following iki_read commands: -# iki_read time.txt +Q -r UTC UTC -w -WW character "'" "'" code '"' '"' -# -# To read the "Time Documentation" section of this file, use this command sequence: -# fss_basic_list_read time.txt +Q -cn "Time Documentation" | iki_read +Q -r UTC UTC -w -WW character "'" "'" code '"' '"' -# - -Time Documentation: - This documents a unit of measurement called a bold:"Time", represented with uppercase bold:"T". - For comparison, a unit of bold:"Time" is equivalent to a nanosecond, or 10^-9 seconds. - A bold:"MegaTime (MT)" is therefore equivalent to a millisecond such that a millisecond is 10^-3 seconds. - - A unit of bold:"Time" is intended to represent some unit of bold:"Time" such that a single 64-bit integer may hold all units of bold:"Time" for a single calendar year. - This unit of bold:"Time" does not and must not include bold:"Years" (unlike bold:"Unix time"). - To convert from bold:"Time" to bold:"Unix time", one must have a year (which could be assumed to be the current year) and then calculate all of those calendar oddities. - - A unit of bold:"Time" by default is assumed to be in UTC:"Coordinated Universal Time". - - code:"1 (Earth) year ~= 31536000000000000 Time or 31536000 GT (GigaTime)". - - code:"1 (Earth) day = 86400000000000 Time or 86400 GT (GigaTime)". - - code:"1 (Earth) hour = 3600000000000 Time or 3600 GT (GigaTime)". - - code:"1 (Earth) minute = 60000000000 Time or 60 GT (GigaTime)". - - code:"1 (Earth) second = 1000000000 Time or 1 GT (GigaTime)". - - Consequentially, 1 day is easily represented in units of bold:"Time" as code:"86.4 TT (TeraTime)". - - The Time may be stored in its "year string format". - In this format, a Year may be prepended to the Time followed by a single colon ':' to associate a year with the Time. - This Year has no minimum or maximum but may not have decimals. - For example, "2020:86400000000000" would represent: January 02, 2020 0:00 UTC. - For example, "2020:86.4 TT" would represent: January 02, 2020 0:00 UTC. - - A second unit of bold:"Time", called bold:"EpochTime", works the same way as bold:"Time" except it represents seconds. - This unit is designated code:"ET". - The format is similar to bold:"Time", except there are two colons: code:"1970::1620874738" would represent: code:"May 13, 2021 2:58:58 UTC". - When the year is not specified, then this is identical to bold:"UNIX Epoch". - - A unit of bold:"EpochTime" by default is assumed to be in UTC:"Coordinated Universal Time". - - code:"1 (Earth) year ~= 31536000 EpochTime or 31.536 GE (GigaEpochTime)". - - code:"1 (Earth) day = 86400 EpochTime". - - code:"1 (Earth) hour = 3600 EpochTime". - - code:"1 (Earth) minute = 60 EpochTime". - - code:"1 (Earth) second = 1 EpochTime". - - code:"1 GT (GigaTime) = 1 EpochTime". - - Consequentially, 1 day is easily represented in units of bold:"EpochTime" as code:"86.4 KE (KiloEpochTime)". - - See the specification file:"time.txt" for more precise technical details. diff --git a/sources/c/init/string.h b/sources/c/init/string.h index ee5598d..3e3aac5 100644 --- a/sources/c/init/string.h +++ b/sources/c/init/string.h @@ -37,8 +37,8 @@ extern "C" { #define CONTROLLER_default_path_pid_s _override_controller_path_pid_ #define CONTROLLER_default_path_pid_s_length _override_controller_path_pid_length_ #else - #define CONTROLLER_init_default_path_pid_s "/var/run/init" - #define CONTROLLER_init_default_path_pid_s_length 13 + #define CONTROLLER_init_default_path_pid_s "/run/init" + #define CONTROLLER_init_default_path_pid_s_length 9 #endif // defined(_override_controller_path_pid_) && defined(_override_controller_path_pid_length_) // The pid prefix is a system-specific path part and needs to be more easily controlled at compile time. @@ -65,8 +65,8 @@ extern "C" { #define CONTROLLER_default_path_socket_s _override_controller_path_socket_ #define CONTROLLER_default_path_socket_s_length _override_controller_path_socket_length_ #else - #define CONTROLLER_init_default_path_socket_s "/var/run/init" - #define CONTROLLER_init_default_path_socket_s_length 13 + #define CONTROLLER_init_default_path_socket_s "/run/init" + #define CONTROLLER_init_default_path_socket_s_length 9 #endif // defined(_override_controller_path_socket_) && defined(_override_controller_path_socket_length_) // The socket prefix path is a system-specific path part and needs to be more easily controlled at compile time. diff --git a/sources/c/main/common/type/process.h b/sources/c/main/common/type/process.h index 108f5d9..7a9af34 100644 --- a/sources/c/main/common/type/process.h +++ b/sources/c/main/common/type/process.h @@ -22,6 +22,7 @@ extern "C" { * The typedef for this is located in the defs.h header. * * Properties: + * - flag: Flags from controller_process_flag_*_e. * - ready: State representing if the settings are all loaded and is ready to run program operations. * - mode: Controller setting mode based on the setting mode enumerator. * @@ -41,6 +42,7 @@ extern "C" { */ #ifndef _di_controller_process_t struct controller_process_t_ { + uint8_t flag; uint8_t ready; uint8_t mode; @@ -63,6 +65,7 @@ extern "C" { 0, \ 0, \ 0, \ + 0, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ diff --git a/sources/c/main/entry/process.c b/sources/c/main/entry/process.c index bf6992c..630932a 100644 --- a/sources/c/main/entry/process.c +++ b/sources/c/main/entry/process.c @@ -184,7 +184,7 @@ extern "C" { break; } else if (entry_action->type == controller_entry_action_type_consider_e || controller_entry_action_type_is_rule(entry_action->type)) { - status_lock = controller_lock_write(is_entry, &main->thread, &main->thread.lock.rule); + status_lock = controller_lock_write(is_entry, F_true, &main->thread, &main->thread.lock.rule); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); @@ -212,7 +212,7 @@ extern "C" { id_rule_name[entry_action->parameters.array[0].used] = f_path_separator_s.string[0]; id_rule_name[id_rule_length] = 0; - status_lock = controller_lock_read(is_entry, &main->thread, &main->thread.lock.rule); + status_lock = controller_lock_read(is_entry, F_true, &main->thread, &main->thread.lock.rule); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); @@ -249,7 +249,7 @@ extern "C" { memcpy(cache_name_item, cache->action.name_item.string, sizeof(f_char_t) * cache->action.name_item.used); memcpy(cache_name_file, cache->action.name_file.string, sizeof(f_char_t) * cache->action.name_file.used); - status_lock = controller_lock_write(is_entry, &main->thread, &main->thread.lock.rule); + status_lock = controller_lock_write(is_entry, F_true, &main->thread, &main->thread.lock.rule); if (F_status_is_fine(status_lock)) { status = controller_rule_read(main, cache, is_entry, alias_rule, entry, &main->process.rules.array[main->process.rules.used]); @@ -421,7 +421,7 @@ extern "C" { return F_status_is_error(F_critical); } else { - main->setting.flag |= controller_process_flag_failsafe_e; + main->process.flag |= controller_process_flag_failsafe_e; main->process.failsafe_item_id = entry_action->number; controller_print_output_entry_setting_simulate_value(&main->program.output, is_entry, controller_failsafe_s, f_string_empty_s, entry->items.array[main->process.failsafe_item_id].name, f_string_empty_s); diff --git a/sources/c/main/instance/prepare.c b/sources/c/main/instance/prepare.c index c43df96..8000df5 100644 --- a/sources/c/main/instance/prepare.c +++ b/sources/c/main/instance/prepare.c @@ -14,7 +14,7 @@ extern "C" { if (controller_instance_find(action, alias, main->thread.instances, id) == F_false) { f_thread_unlock(&main->thread.lock.instance); - status = controller_lock_write(is_normal, &main->thread, &main->thread.lock.instance); + status = controller_lock_write(is_normal, F_true, &main->thread, &main->thread.lock.instance); if (F_status_is_error(status)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status), F_false); @@ -36,7 +36,7 @@ extern "C" { controller_instance_t * const instance = F_status_is_error_not(status) ? main->thread.instances.array[main->thread.instances.used] : 0; if (F_status_is_error_not(status)) { - status = controller_lock_write(is_normal, &main->thread, &instance->lock); + status = controller_lock_write(is_normal, F_true, &main->thread, &instance->lock); } if (F_status_is_error(status)) { @@ -65,8 +65,8 @@ extern "C" { f_thread_unlock(&main->thread.lock.instance); // The read lock must be restored on return. - const f_status_t status_restore = F_status_is_error(controller_lock_read(is_normal, &main->thread, &main->thread.lock.instance)) - ? F_status_set_error(F_lock) + const f_status_t status_restore = F_status_is_error(controller_lock_read(is_normal, F_false, &main->thread, &main->thread.lock.instance)) + ? F_status_set_error(F_lock_read) : F_okay; if (F_status_is_fine(status)) { diff --git a/sources/c/main/instance/prepare.h b/sources/c/main/instance/prepare.h index ade62d6..0af2e85 100644 --- a/sources/c/main/instance/prepare.h +++ b/sources/c/main/instance/prepare.h @@ -46,7 +46,7 @@ extern "C" { * F_okay on success. * F_found on success, but nothing was done because an existing instance was found. * - * F_lock (with error bit) if failed to re-establish read lock on main.thread.lock.instance while returning. + * F_lock_read (with error bit) if failed to re-establish read lock on main.thread.lock.instance while returning. * F_parameter (with error bit) if a parameter is invalid. * * Errors (with error bit) from: f_string_dynamic_append(). diff --git a/sources/c/main/lock.c b/sources/c/main/lock.c index 75b4dc6..59ff2c6 100644 --- a/sources/c/main/lock.c +++ b/sources/c/main/lock.c @@ -40,7 +40,7 @@ extern "C" { #endif // _di_controller_lock_create_ #ifndef _di_controller_lock_read_ - f_status_t controller_lock_read(const uint8_t is_normal, controller_thread_t * const thread, f_thread_lock_t * const lock) { + f_status_t controller_lock_read(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_lock_t * const lock) { if (!thread || !lock) return F_status_set_error(F_parameter); @@ -55,7 +55,7 @@ extern "C" { status = f_thread_lock_read_timed(&time, lock); if (status == F_time) { - if (!controller_thread_is_enabled(is_normal, thread)) return F_status_set_error(F_interrupt); + if (check && !controller_thread_is_enabled(is_normal, thread)) return F_status_set_error(F_interrupt); } else { break; @@ -71,21 +71,12 @@ extern "C" { if (!instance || !instance->main || !lock) return F_status_set_error(F_parameter); - return controller_lock_read_instance_type(instance->type, &instance->main->thread, lock); + return controller_lock_read(instance->type != controller_instance_type_exit_e, F_true, &instance->main->thread, lock); } #endif // _di_controller_lock_read_instance_ -#ifndef _di_controller_lock_read_instance_type_ - f_status_t controller_lock_read_instance_type(const uint8_t type, controller_thread_t * const thread, f_thread_lock_t * const lock) { - - if (!thread || !lock) return F_status_set_error(F_parameter); - - return controller_lock_read(type != controller_instance_type_exit_e, thread, lock); - } -#endif // _di_controller_lock_read_instance_type_ - #ifndef _di_controller_lock_write_ - f_status_t controller_lock_write(const uint8_t is_normal, controller_thread_t * const thread, f_thread_lock_t * const lock) { + f_status_t controller_lock_write(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_lock_t * const lock) { if (!thread || !lock) return F_status_set_error(F_parameter); @@ -98,7 +89,7 @@ extern "C" { status = f_thread_lock_write_timed(&time, lock); if (status == F_time) { - if (!controller_thread_is_enabled(is_normal, thread)) return F_status_set_error(F_interrupt); + if (check && !controller_thread_is_enabled(is_normal, thread)) return F_status_set_error(F_interrupt); } else { break; @@ -114,19 +105,10 @@ extern "C" { if (!instance || !lock) return F_status_set_error(F_parameter); - return controller_lock_write_instance_type(instance->type, &instance->main->thread, lock); + return controller_lock_write(instance->type != controller_instance_type_exit_e, F_true, &instance->main->thread, lock); } #endif // _di_controller_lock_write_instance_ -#ifndef _di_controller_lock_write_instance_type_ - f_status_t controller_lock_write_instance_type(const uint8_t type, controller_thread_t * const thread, f_thread_lock_t * const lock) { - - if (!thread || !lock) return F_status_set_error(F_parameter); - - return controller_lock_write(type != controller_instance_type_exit_e, thread, lock); - } -#endif // _di_controller_lock_write_instance_type_ - #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/main/lock.h b/sources/c/main/lock.h index f63f1a1..a011543 100644 --- a/sources/c/main/lock.h +++ b/sources/c/main/lock.h @@ -47,6 +47,9 @@ extern "C" { * @param is_normal * If TRUE, then perform as if this operates during a normal operation (Entry and Control). * If FALSE, then perform as if this operates during a an Exit operation. + * @param check + * If TRUE, then check if the state is enabled and if it is not then abort. + * If FALSE, then do not check if the state is enabled and keep looping. * @param thread * The thread data used to determine if the main thread is disabled or not. * @@ -69,7 +72,7 @@ extern "C" { * @see f_thread_lock_read_timed() */ #ifndef _di_controller_lock_read_ - extern f_status_t controller_lock_read(const uint8_t is_normal, controller_thread_t * const thread, f_thread_lock_t * const lock); + extern f_status_t controller_lock_read(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_lock_t * const lock); #endif // _di_controller_lock_read_ /** @@ -100,35 +103,6 @@ extern "C" { #endif // _di_controller_lock_read_instance_ /** - * Wait to get a read lock for some instance type. - * - * Given a r/w lock, periodically check to see if main thread is disabled while waiting. - * - * @param type - * The instance type to use when checking if thread is enabled. - * @param thread - * The thread data used to determine if the main thread is disabled or not. - * - * Must not be NULL. - * @param lock - * The r/w lock to obtain a read lock on. - * - * Must not be NULL. - * - * @return - * Status from: controller_lock_read(). - * - * F_parameter (with error bit) if a parameter is invalid. - * - * Errors (with error bit) from: controller_lock_read(). - * - * @see controller_lock_read() - */ -#ifndef _di_controller_lock_read_instance_type_ - extern f_status_t controller_lock_read_instance_type(const uint8_t type, controller_thread_t * const thread, f_thread_lock_t * const lock); -#endif // _di_controller_lock_read_instance_type_ - -/** * Wait to get a write lock. * * Given a r/w lock, periodically check to see if main thread is disabled while waiting. @@ -136,6 +110,9 @@ extern "C" { * @param is_normal * If TRUE, then perform as if this operates during a normal operation (Entry and Control). * If FALSE, then perform as if this operates during a an Exit operation. + * @param check + * If TRUE, then check if the state is enabled and if it is not then abort. + * If FALSE, then do not check if the state is enabled and keep looping. * @param thread * The thread data used to determine if the main thread is disabled or not. * @@ -158,7 +135,7 @@ extern "C" { * @see f_thread_lock_write_timed() */ #ifndef _di_controller_lock_write_ - extern f_status_t controller_lock_write(const uint8_t is_normal, controller_thread_t * const thread, f_thread_lock_t * const lock); + extern f_status_t controller_lock_write(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_lock_t * const lock); #endif // _di_controller_lock_write_ /** @@ -176,35 +153,6 @@ extern "C" { * Must not be NULL. * * @return - * Status from: controller_lock_write_instance_type(). - * - * F_parameter (with error bit) if a parameter is invalid. - * - * Errors (with error bit) from: controller_lock_write_instance_type(). - * - * @see controller_lock_write_instance_type() - */ -#ifndef _di_controller_lock_write_instance_ - extern f_status_t controller_lock_write_instance(controller_instance_t * const instance, f_thread_lock_t * const lock); -#endif // _di_controller_lock_write_instance_ - -/** - * Wait to get a write lock for some instance type. - * - * Given a r/w lock, periodically check to see if main thread is disabled while waiting. - * - * @param type - * The instance type to use when checking if thread is enabled. - * @param thread - * The thread data used to determine if the main thread is disabled or not. - * - * Must not be NULL. - * @param lock - * The r/w lock to obtain a write lock on. - * - * Must not be NULL. - * - * @return * Status from: controller_lock_write(). * * F_parameter (with error bit) if a parameter is invalid. @@ -213,9 +161,9 @@ extern "C" { * * @see controller_lock_write() */ -#ifndef _di_controller_lock_write_instance_type_ - extern f_status_t controller_lock_write_instance_type(const uint8_t type, controller_thread_t * const thread, f_thread_lock_t * const lock); -#endif // _di_controller_lock_write_instance_type_ +#ifndef _di_controller_lock_write_instance_ + extern f_status_t controller_lock_write_instance(controller_instance_t * const instance, f_thread_lock_t * const lock); +#endif // _di_controller_lock_write_instance_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/main/perform.c b/sources/c/main/perform.c index f2115e6..80f769d 100644 --- a/sources/c/main/perform.c +++ b/sources/c/main/perform.c @@ -38,7 +38,7 @@ extern "C" { status = F_okay; } else { - main->setting.flag |= controller_process_flag_pid_created_e; + main->process.flag |= controller_process_flag_pid_created_e; controller_print_debug_perform_pid_file_create_success(&main->program.debug); } diff --git a/sources/c/main/rule/execute.c b/sources/c/main/rule/execute.c index b19cea0..d7598be 100644 --- a/sources/c/main/rule/execute.c +++ b/sources/c/main/rule/execute.c @@ -320,7 +320,7 @@ extern "C" { if (instance->rule.items.array[i].pid_file.used) { do { - status = controller_rule_execute_pid_with(instance->rule.items.array[i].pid_file, instance->rule.items.array[i].type, f_string_empty_s, instance->cache.expanded, options, instance->rule.items.array[i].with, &execute_set, instance); + status = controller_rule_execute_pid_with(instance, instance->rule.items.array[i].pid_file, instance->rule.items.array[i].type, f_string_empty_s, instance->cache.expanded, options, instance->rule.items.array[i].with, &execute_set); if (status == F_child || F_status_set_fine(status) == F_interrupt || F_status_set_fine(status) == F_lock) break; if (F_status_is_error(status) && F_status_set_fine(status) != F_failure) break; @@ -364,7 +364,7 @@ extern "C" { } do { - status = controller_rule_execute_pid_with(instance->rule.items.array[i].pid_file, instance->rule.items.array[i].type, instance->rule.engine.used ? instance->rule.engine : controller_default_engine_s, instance->rule.engine_arguments, options, instance->rule.items.array[i].with, &execute_set, instance); + status = controller_rule_execute_pid_with(instance, instance->rule.items.array[i].pid_file, instance->rule.items.array[i].type, instance->rule.engine.used ? instance->rule.engine : controller_default_engine_s, instance->rule.engine_arguments, options, instance->rule.items.array[i].with, &execute_set); if (status == F_child || F_status_set_fine(status) == F_interrupt || F_status_set_fine(status) == F_lock) break; if (F_status_is_error(status) && F_status_set_fine(status) != F_failure) break; @@ -407,7 +407,7 @@ extern "C" { // Lock failed, attempt to re-establish lock before returning. if (F_status_set_fine(status) == F_lock) { - status = controller_lock_read(instance->type != controller_instance_type_exit_e, &main->thread, &instance->lock); + status = controller_lock_read(instance->type != controller_instance_type_exit_e, F_true, &main->thread, &instance->lock); if (F_status_is_error(status)) return F_status_set_error(F_lock); success = F_false; @@ -432,7 +432,6 @@ extern "C" { if (!instance || !instance->main) return F_status_set_error(F_parameter); f_status_t status = F_okay; - f_status_t status_lock = F_okay; controller_t * const main = instance->main; @@ -446,23 +445,8 @@ extern "C" { return status; } - pid_t *child = 0; + pid_t * const process_child_id = controller_rule_execute_next_child(instance); - { - f_number_unsigned_t i = 0; - - while (i < instance->childs.used && instance->childs.array[i]) { - ++i; - } // while - - child = &instance->childs.array[i]; - - if (i == instance->childs.used) { - ++instance->childs.used; - } - } - - // @fixme don't actually execute as even executing "bash" could be bad if the shell being run is something nefarious. if (options & controller_instance_option_simulate_e) { controller_print_entry_output_execute_simulate(&main->program.output, instance, program, arguments); @@ -488,72 +472,46 @@ extern "C" { const pid_t id_child = result.pid; result.status = 0; - f_thread_unlock(&instance->lock); - - status_lock = controller_lock_write_instance(instance, &instance->lock); - - if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); - - if (F_status_set_fine(status_lock) != F_interrupt) { - status = controller_lock_read_instance(instance, &instance->lock); - if (status == F_okay) return status_lock; - } - - return F_status_set_error(F_lock); - } - // Assign the child instance id to allow for the cancel instance to send appropriate termination signals to the child instance. - *child = id_child; - - f_thread_unlock(&instance->lock); - - status_lock = controller_lock_read_instance(instance, &instance->lock); + *process_child_id = id_child; - if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); - } - - if (F_status_set_fine(status_lock) != F_interrupt) { - - // Have the parent wait for the child instance to finish. - waitpid(id_child, &result.status, 0); - } - - if (F_status_set_fine(status_lock) == F_interrupt || !controller_thread_is_enabled_instance(instance)) { - return status_lock == F_okay ? F_status_set_error(F_interrupt) : F_status_set_error(F_lock); - } + // Have the parent wait for the child instance to finish. + waitpid(id_child, &result.status, 0); - if (status_lock == F_okay) { - f_thread_unlock(&instance->lock); - } + f_thread_unlock(&instance->lock); - status_lock = controller_lock_write_instance(instance, &instance->lock); + f_status_t status_lock = controller_lock_write_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); - if (F_status_set_fine(status_lock) != F_interrupt) { - status = controller_lock_read_instance(instance, &instance->lock); - if (status == F_okay) return status_lock; - } + status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &instance->main->thread, &instance->lock); + if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); - return F_status_set_error(F_lock); + return F_status_set_error(F_lock_write); } instance->result = result.status; // Remove the pid now that waidpid() has returned. - *child = 0; + *process_child_id = 0; f_thread_unlock(&instance->lock); status_lock = controller_lock_read_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); - return F_status_set_error(F_lock); + // Try again, after the first interrupt. + if (F_status_set_fine(status_lock) == F_interrupt) { + status_lock = controller_lock_read_instance(instance, &instance->lock); + } + + if (F_status_is_error(status_lock)) { + controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); + + return F_status_set_error(F_lock_read); + } } if (WIFEXITED(result.status) ? WEXITSTATUS(result.status) : 0) { @@ -599,13 +557,50 @@ extern "C" { } #endif // _di_controller_rule_execute_foreground_ +#ifndef _di_controller_rule_execute_next_child_ + pid_t * controller_rule_execute_next_child(controller_instance_t * const instance) { + + if (!instance) return 0; + + f_number_unsigned_t i = 0; + + while (i < instance->childs.used && instance->childs.array[i]) { + ++i; + } // while + + if (i == instance->childs.used) { + ++instance->childs.used; + } + + return &instance->childs.array[i]; + } +#endif // _di_controller_rule_execute_next_child_ + +#ifndef _di_controller_rule_execute_next_pid_path_ + f_string_dynamic_t * controller_rule_execute_next_pid_path(controller_instance_t * const instance) { + + if (!instance) return 0; + + f_number_unsigned_t i = 0; + + while (i < instance->path_pids.used && instance->path_pids.array[i].used) { + ++i; + } // while + + if (i == instance->path_pids.used) { + ++instance->path_pids.used; + } + + return &instance->path_pids.array[i]; + } +#endif // _di_controller_rule_execute_next_pid_path_ + #ifndef _di_controller_rule_execute_pid_with_ - f_status_t controller_rule_execute_pid_with(const f_string_dynamic_t pid_file, const uint8_t type, const f_string_static_t program, const f_string_statics_t arguments, const uint8_t options, const uint8_t with, controller_execute_set_t * const execute_set, controller_instance_t * const instance) { + f_status_t controller_rule_execute_pid_with(controller_instance_t * const instance, const f_string_dynamic_t pid_file, const uint8_t type, const f_string_static_t program, const f_string_statics_t arguments, const uint8_t options, const uint8_t with, controller_execute_set_t * const execute_set) { if (!execute_set || !instance || !instance->main) return F_status_set_error(F_parameter); f_status_t status = F_okay; - f_status_t status_lock = F_okay; controller_t * const main = instance->main; @@ -627,44 +622,18 @@ extern "C" { return status; } - pid_t *child = 0; - f_string_dynamic_t *child_pid_file = 0; - - { - f_number_unsigned_t i = 0; - - while (i < instance->childs.used && instance->childs.array[i]) { - ++i; - } // while - - child = &instance->childs.array[i]; - - if (i == instance->childs.used) { - ++instance->childs.used; - } - - i = 0; - - while (i < instance->path_pids.used && instance->path_pids.array[i].used) { - ++i; - } // while - - child_pid_file = &instance->path_pids.array[i]; - - if (i == instance->path_pids.used) { - ++instance->path_pids.used; - } - } + pid_t * const process_child_id = controller_rule_execute_next_child(instance); + f_string_dynamic_t * const process_child_pid_file = controller_rule_execute_next_pid_path(instance); status = f_file_exists(pid_file, F_true); if (F_status_is_error(status) || status == F_true) { - controller_print_error_file_status(&main->program.error, macro_controller_f(f_file_exists), pid_file, f_file_operation_find_s, fll_error_file_type_file_e, status == F_true ? F_file_found : F_status_set_fine(status)); + controller_print_error_file_status(&main->program.error, macro_controller_f(f_file_exists), pid_file, status == F_true ? f_file_operation_create_s : f_file_operation_find_s, fll_error_file_type_file_e, status == F_true ? F_file_found : F_status_set_fine(status)); return status; } - status = f_string_dynamic_append_nulless(pid_file, child_pid_file); + status = f_string_dynamic_append_nulless(pid_file, process_child_pid_file); if (F_status_is_error(status)) { controller_print_error_status(&main->program.error, macro_controller_f(f_string_dynamic_append_nulless), F_status_set_fine(status)); @@ -704,31 +673,27 @@ extern "C" { const pid_t id_child = result.pid; result.status = 0; + // Assign the child instance id to allow for the cancel instance to send appropriate termination signals to the child instance. + *process_child_id = id_child; + + // Have the parent wait for the child instance to finish. + waitpid(id_child, &result.status, 0); + f_thread_unlock(&instance->lock); - status_lock = controller_lock_write_instance(instance, &instance->active); + f_status_t status_lock = controller_lock_write_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); - if (F_status_set_fine(status_lock) != F_interrupt) { - status = controller_lock_read_instance(instance, &instance->active); - if (status == F_okay) return status_lock; - } + status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &instance->main->thread, &instance->lock); + if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); - return F_status_set_error(F_lock); + return F_status_set_error(F_lock_write); } // Assign the child instance id to allow for the cancel instance to send appropriate termination signals to the child instance. - *child = id_child; - - f_thread_unlock(&instance->lock); - - status_lock = controller_lock_read_instance(instance, &instance->active); - - if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); - } + *process_child_id = id_child; // The child instance should perform the change into background, therefore it is safe to wait for the child to Exit (another instance is spawned). if (F_status_set_fine(status_lock) != F_interrupt) { @@ -741,27 +706,25 @@ extern "C" { f_thread_unlock(&instance->lock); } - status_lock = controller_lock_write_instance(instance, &instance->active); + status_lock = controller_lock_write_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); - if (F_status_set_fine(status_lock) != F_interrupt) { - status = controller_lock_read_instance(instance, &instance->active); - if (status == F_okay) return status_lock; - } + status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &instance->main->thread, &instance->lock); + if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); - return F_status_set_error(F_lock); + return F_status_set_error(F_lock_write); } instance->result = result.status; // Remove the pid now that waidpid() has returned. - *child = 0; + *process_child_id = 0; f_thread_unlock(&instance->lock); - status_lock = controller_lock_read_instance(instance, &instance->active); + status_lock = controller_lock_read_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); diff --git a/sources/c/main/rule/execute.h b/sources/c/main/rule/execute.h index 4fa12be..6648e20 100644 --- a/sources/c/main/rule/execute.h +++ b/sources/c/main/rule/execute.h @@ -41,8 +41,10 @@ extern "C" { * @param options * Process options to consider when executing. * If bit controller_instance_option_simulate_e, then the Rule execution is in simulation mode (printing a message that the Rule would be executed but does not execute the rule). - * @param process - * The process data for processing this Rule. + * @param instance + * The instance data. + * + * Must not be NULL. * * @return * F_okay on success. @@ -77,15 +79,20 @@ extern "C" { * If bit controller_instance_option_simulate_e, then the Rule execution is in simulation mode (printing a message that the Rule would be executed but does not execute the rule). * @param execute_set * The execute parameter and as settings. - * @param process - * The process data for processing this Rule. + * + * Must not be NULL. + * @param instance + * The instance data. + * + * Must not be NULL. * * @return * F_okay on success. * F_child on child process exiting. * * F_interrupt (with error bit) on receiving a process signal, such as an interrupt signal. - * F_lock (with error bit) if failed to re-establish read lock on process->lock while returning. + * F_lock_read (with error bit) if failed to re-establish read lock on process->lock while returning. + * F_lock_write (with error bit) if failed to establish write lock on process->lock, and the read lock is able to be restored. * * Errors (with error bit) from: fll_execute_program(). * @@ -96,6 +103,44 @@ extern "C" { #endif // _di_controller_rule_execute_foreground_ /** + * Find the next available child slot and return a pointer to that location. + * + * @param instance + * The instance data. + * + * instance.childs.used is incremented on success if the last available position is at the "used" position in the array. + * + * Must not be NULL. + * + * @return + * A pointer the next avialable child pid_t slot in the instance. + * + * NULL on error. + */ +#ifndef _di_controller_rule_execute_next_child_ + extern pid_t * controller_rule_execute_next_child(controller_instance_t * const instance); +#endif // _di_controller_rule_execute_next_child_ + +/** + * Find the next available PID path slot and return a pointer to that location. + * + * @param instance + * The instance data. + * + * instance.path_pids.used is incremented on success if the last available position is at the "used" position in the array. + * + * Must not be NULL. + * + * @return + * A pointer the next avialable PID path f_string_dynamic_t slot in the instance. + * + * NULL on error. + */ +#ifndef _di_controller_rule_execute_next_pid_path_ + extern f_string_dynamic_t * controller_rule_execute_next_pid_path(controller_instance_t * const instance); +#endif // _di_controller_rule_execute_next_pid_path_ + +/** * Perform an execution of the given Rule in the foreground or background and creating a PID file. * * This requires that a read lock be set on process->lock before being called. @@ -118,8 +163,12 @@ extern "C" { * The "with" option flags. * @param execute_set * The execute parameter and as settings. - * @param process - * The process data for processing this Rule. + * + * Must not be NULL. + * @param instance + * The instance data. + * + * Must not be NULL. * * @return * F_okay on success. @@ -127,14 +176,15 @@ extern "C" { * * F_file_found (with error bit) if the PID file already exists. * F_interrupt (with error bit) on receiving a process signal, such as an interrupt signal. - * F_lock (with error bit) if failed to re-establish read lock on process->lock while returning. + * F_lock_read (with error bit) if failed to re-establish read lock on process->lock while returning. + * F_lock_write (with error bit) if failed to establish write lock on process->lock, and the read lock is able to be restored. * * Errors (with error bit) from: fll_execute_program(). * * @see fll_execute_program() */ #ifndef _di_controller_rule_execute_pid_with_ - extern f_status_t controller_rule_execute_pid_with(const f_string_dynamic_t pid_file, const uint8_t type, const f_string_static_t program, const f_string_statics_t arguments, const uint8_t options, const uint8_t with, controller_execute_set_t * const execute_set, controller_instance_t * const instance); + extern f_status_t controller_rule_execute_pid_with(controller_instance_t * const instance, const f_string_dynamic_t pid_file, const uint8_t type, const f_string_static_t program, const f_string_statics_t arguments, const uint8_t options, const uint8_t with, controller_execute_set_t * const execute_set); #endif // _di_controller_rule_execute_pid_with_ /** diff --git a/sources/c/main/rule/instance.c b/sources/c/main/rule/instance.c index 1ca940f..e0b805d 100644 --- a/sources/c/main/rule/instance.c +++ b/sources/c/main/rule/instance.c @@ -533,7 +533,7 @@ extern "C" { return F_status_set_error(F_interrupt); } - f_status_t status = controller_lock_read_instance_type(type, &main->thread, &main->thread.lock.instance); + f_status_t status = controller_lock_read(type != controller_instance_type_exit_e, F_true, &main->thread, &main->thread.lock.instance); if (F_status_is_error(status)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status), F_true); @@ -555,7 +555,7 @@ extern "C" { controller_instance_t * const instance = main->thread.instances.array[at]; - status = controller_lock_read_instance_type(type, &main->thread, &instance->active); + status = controller_lock_read(type != controller_instance_type_exit_e, F_true, &main->thread, &instance->active); if (F_status_is_error(status)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status), F_true); diff --git a/sources/c/main/rule/wait.c b/sources/c/main/rule/wait.c index 177c756..3274a3e 100644 --- a/sources/c/main/rule/wait.c +++ b/sources/c/main/rule/wait.c @@ -9,7 +9,7 @@ extern "C" { if (!main) return F_status_set_error(F_parameter); - f_status_t status_lock = controller_lock_read(is_normal, &main->thread, &main->thread.lock.instance); + f_status_t status_lock = controller_lock_read(is_normal, F_false, &main->thread, &main->thread.lock.instance); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); @@ -45,7 +45,7 @@ extern "C" { if (!controller_thread_is_enabled(is_normal, &main->thread)) break; // Re-establish instance read lock to wait for or protect from the cleanup thread while checking the read instance. - status_lock = controller_lock_read(is_normal, &main->thread, &main->thread.lock.instance); + status_lock = controller_lock_read(is_normal, F_true, &main->thread, &main->thread.lock.instance); if (F_status_is_error(status_lock)) break; if (!instance_list[i]) { @@ -54,7 +54,7 @@ extern "C" { continue; } - status_lock = controller_lock_read(is_normal, &main->thread, &instance_list[i]->active); + status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->active); if (F_status_is_error(status_lock)) { f_thread_unlock(&main->thread.lock.instance); @@ -65,7 +65,7 @@ extern "C" { // Once the active lock is obtained, then the main instance read lock can be safely released. f_thread_unlock(&main->thread.lock.instance); - status_lock = controller_lock_read(is_normal, &main->thread, &instance_list[i]->lock); + status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->lock); if (F_status_is_error(status_lock)) { f_thread_unlock(&instance_list[i]->active); @@ -87,7 +87,7 @@ extern "C" { if (instance_list[i]->state == controller_instance_state_done_e) { f_thread_unlock(&instance_list[i]->lock); - status_lock = controller_lock_write(is_normal, &main->thread, &instance_list[i]->lock); + status_lock = controller_lock_write(is_normal, F_true, &main->thread, &instance_list[i]->lock); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); @@ -112,7 +112,7 @@ extern "C" { f_thread_mutex_unlock(&instance_list[i]->wait_lock); } - status_lock = controller_lock_read(is_normal, &main->thread, &instance_list[i]->active); + status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->active); if (F_status_is_error(status_lock)) { f_thread_unlock(&instance_list[i]->lock); @@ -123,7 +123,7 @@ extern "C" { f_thread_unlock(&instance_list[i]->lock); - status_lock = controller_lock_read(is_normal, &main->thread, &instance_list[i]->lock); + status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->lock); if (F_status_is_error(status_lock)) break; } @@ -160,7 +160,7 @@ extern "C" { break; } - status_lock = controller_lock_read(is_normal, &main->thread, &instance_list[i]->lock); + status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->lock); if (F_status_is_error(status_lock)) { f_thread_unlock(&instance_list[i]->active); diff --git a/sources/c/main/thread/entry.c b/sources/c/main/thread/entry.c index e63c57f..e9be5e7 100644 --- a/sources/c/main/thread/entry.c +++ b/sources/c/main/thread/entry.c @@ -47,7 +47,7 @@ extern "C" { if (F_status_is_error(*status)) { main->process.ready = controller_process_ready_fail_e; - if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (main->setting.flag & controller_process_flag_failsafe_e)) { + if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (main->process.flag & controller_process_flag_failsafe_e)) { const uint8_t original_enabled = main->thread.enabled; // Restore operating mode so that the failsafe can execute. @@ -158,7 +158,7 @@ extern "C" { if (F_status_is_error(*status)) { main->process.ready = controller_process_ready_fail_e; - if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (main->setting.flag & controller_process_flag_failsafe_e)) { + if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (main->process.flag & controller_process_flag_failsafe_e)) { const uint8_t original_enabled = main->thread.enabled; diff --git a/specifications/time.txt b/specifications/time.txt deleted file mode 100644 index ddde71f..0000000 --- a/specifications/time.txt +++ /dev/null @@ -1,156 +0,0 @@ -# fss-0002 iki-0000 -# -# license: open-standard-license-1.0-or-later -# version 2024/07/02 -# -# This file (assumed to be named time.txt) can be more easily read using the following iki_read commands: -# iki_read time.txt +Q -r UTC UTC -w -WW character "'" "'" code '"' '"' -# -# To read the "Time Specification" section of this file, use this command sequence: -# fss_basic_list_read time.txt +Q -cn "Time Specification" | iki_read +Q -r UTC UTC -w -WW character "'" "'" code '"' '"' -# - -Time Specification: - There are two units of bold:"Time", the first is simply called bold:"Time" and the second is called bold:"EpochTime". - - Both bold:"Time" and bold:"EpochTime" are measured without the year but may contain a year to designate the point in the counting begins. - These are both represented by a single 64-bit (unsigned) integer. - The default timezone is always UTC:"Coordinated Universal Time". - - The common form is intended as the non-technical form that is form common use. - This may have a negative value or be more than 64-bit digits long. - This is simply not expected to be interpreted as a unit of time on a computer (but nothing stops it from being interpreted). - - The technical forms are limit to 64-bit unsigned for technical use but should technology advance to a point where larger bits are needed then this allows for that. - The systems should expect 64-bit and larger bits would have to become common before something larger than 64-bit is the expected or assumed default. - Negative signs can be allowed but they must not prevent the full use of the 64-bit. - The implementation of how this is done is left to the implementer except that the signs are immediately to the left of the digit. - For example code:"2022:-5" would be 5 units after the start of the year 2022. - Because the negative is allowed, so must the positive character (such as code:"2022:+5"). - A positive value is the default interpretation when no sign is valid. - - The unit of time called bold:"Time" is counted increments of a nanosecond, or 10^-9 seconds. - A unit of bold:"Time" is, therefore, equivalent to a nanosecond. - The default year for bold:"Time" is the current year. - - The unit of time called bold:"EpochTime" is counted increments of a second, or 10^-9 seconds. - A unit of bold:"EpochTime" is, therefore, equivalent to a second. - The default year for bold:"EpochTime" is the bold:"UNIX Epoch", sometimes called bold:"Unix time". - - The unit bold:"Time" has two technical forms and one common form, with the year and without the year. - - Key\: - code:"\s" = White space. - code:"\d" = The digits used to represent time (a digit). - code:"*" = Zero or more occurrences. - code:"+" = One or more occurrences. - code:":" = A single colon character:":" (unicode:"U+003A"). - code:'"' = A single double-quote character:'"' (unicode:"U+003A"). - - The common form of bold:"Time"\: - - Before Structure\: - code:"". - - Structure\: - code:"\s*\d+\s*\U*\s*". - - After Structure\: - code:"". - - Example\: - code:"86400". - code:"86400 T". - code:"86400 Time". - - The first technical form of bold:"Time"\: - - Before Structure\: - code:"". - - Structure\: - code:"\s*\d+:\d+\s*\U*\s*". - - After Structure\: - code:"". - - Example\: - code:"2022:86400". - code:"2022:86400 T". - code:"2022:86400 Time". - code:"2022:86400 MT". - code:"2022:86400 MegaTime". - - The second technical form of bold:"Time"\: - - Before Structure\: - code:"". - - Structure\: - code:"\s*:\d+\s*\U*\s*". - - After Structure\: - code:"". - - Example\: - code:":86400". - code:":86400 T". - code:":86400 Time". - code:":86400 MT". - code:":86400 MegaTime". - - The unit bold:"EpochTime" has two technical forms and one common form, with the year and without the year. - - The common form of bold:"Time"\: - - Before Structure\: - code:"". - - Structure\: - code:"\s*\d+\s*\U*\s*". - - After Structure\: - code:"". - - Example\: - code:"86400". - code:"86400 ET". - code:"86400 EpochTime". - code:"86400 MET". - code:"86400 MegaEpochTime". - - The first technical form of bold:"EpochTime"\: - - Before Structure\: - code:"". - - Structure\: - code:"\s*\d+::\d+\s*\U*\s*". - - After Structure\: - code:"". - - Example\: - code:"2022::86400". - code:"2022::86400 ET". - code:"2022::86400 EpochTime". - code:"2022::86400 MET". - code:"2022::86400 MegaEpochTime". - - The second technical form of bold:"Time"\: - - Before Structure\: - code:"". - - Structure\: - code:"\s*:\d+\s*\U*\s*". - - After Structure\: - code:"". - - Example\: - code:"::86400". - code:"::86400 ET". - code:"::86400 EpochTime". - code:"::86400 MET". - code:"::86400 MegaEpochTime". -- 1.8.3.1