Adding cpp mocks
This commit is contained in:
106
.cproject
Normal file
106
.cproject
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||||
|
<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.1510091085">
|
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.debug.1510091085" moduleId="org.eclipse.cdt.core.settings" name="Debug">
|
||||||
|
<externalSettings/>
|
||||||
|
<extensions>
|
||||||
|
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
</extensions>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
|
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.debug.1510091085" name="Debug" parent="cdt.managedbuild.config.gnu.cross.exe.debug">
|
||||||
|
<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.1510091085." name="/" resourcePath="">
|
||||||
|
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.574401685" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">
|
||||||
|
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.2118034560" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
|
||||||
|
<builder buildPath="${workspace_loc:/Programming-POSIX-Threads}/Debug" id="cdt.managedbuild.builder.gnu.cross.775897058" managedBuildOn="true" name="Gnu Make Builder.Debug" superClass="cdt.managedbuild.builder.gnu.cross"/>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.c.compiler.743521326" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
|
||||||
|
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.option.optimization.level.991630491" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
|
||||||
|
<option defaultValue="gnu.c.debugging.level.max" id="gnu.c.compiler.option.debugging.level.28681044" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" valueType="enumerated"/>
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1609802857" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.255857520" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
|
||||||
|
<option id="gnu.cpp.compiler.option.optimization.level.371529530" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
|
||||||
|
<option defaultValue="gnu.cpp.compiler.debugging.level.max" id="gnu.cpp.compiler.option.debugging.level.1177570016" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" valueType="enumerated"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.c.linker.2011145861" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker">
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.774239090" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
|
||||||
|
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||||
|
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||||
|
</inputType>
|
||||||
|
</tool>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.934315138" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"/>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.archiver.1399421222" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.assembler.267146708" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1509256621" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||||
|
</tool>
|
||||||
|
</toolChain>
|
||||||
|
</folderInfo>
|
||||||
|
</configuration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
|
</cconfiguration>
|
||||||
|
<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.release.2099010148">
|
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.release.2099010148" moduleId="org.eclipse.cdt.core.settings" name="Release">
|
||||||
|
<externalSettings/>
|
||||||
|
<extensions>
|
||||||
|
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
</extensions>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
|
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.2099010148" name="Release" parent="cdt.managedbuild.config.gnu.cross.exe.release">
|
||||||
|
<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.2099010148." name="/" resourcePath="">
|
||||||
|
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.2065591112" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release">
|
||||||
|
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.323077387" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
|
||||||
|
<builder buildPath="${workspace_loc:/Programming-POSIX-Threads}/Release" id="cdt.managedbuild.builder.gnu.cross.1940584431" managedBuildOn="true" name="Gnu Make Builder.Release" superClass="cdt.managedbuild.builder.gnu.cross"/>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.c.compiler.1471607620" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
|
||||||
|
<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.option.optimization.level.889418414" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
|
||||||
|
<option defaultValue="gnu.c.debugging.level.none" id="gnu.c.compiler.option.debugging.level.849685847" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" valueType="enumerated"/>
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1329892514" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.1318921803" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
|
||||||
|
<option id="gnu.cpp.compiler.option.optimization.level.605394033" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
|
||||||
|
<option defaultValue="gnu.cpp.compiler.debugging.level.none" id="gnu.cpp.compiler.option.debugging.level.1915527540" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" valueType="enumerated"/>
|
||||||
|
</tool>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.c.linker.1454722057" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker">
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.494181964" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
|
||||||
|
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||||
|
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||||
|
</inputType>
|
||||||
|
</tool>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.455636733" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"/>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.archiver.1460190311" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cross.assembler.1037962002" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1811659589" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||||
|
</tool>
|
||||||
|
</toolChain>
|
||||||
|
</folderInfo>
|
||||||
|
</configuration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
|
</cconfiguration>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
|
<project id="Programming-POSIX-Threads.cdt.managedbuild.target.gnu.cross.exe.1111381522" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="scannerConfiguration">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||||
|
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.release.2099010148;cdt.managedbuild.config.gnu.cross.exe.release.2099010148.;cdt.managedbuild.tool.gnu.cross.c.compiler.1471607620;cdt.managedbuild.tool.gnu.c.compiler.input.1329892514">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.1510091085;cdt.managedbuild.config.gnu.cross.exe.debug.1510091085.;cdt.managedbuild.tool.gnu.cross.c.compiler.743521326;cdt.managedbuild.tool.gnu.c.compiler.input.1609802857">
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||||
|
</cproject>
|
||||||
26
.project
Normal file
26
.project
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>Programming-POSIX-Threads</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||||
|
<triggers>full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
25
.settings/language.settings.xml
Normal file
25
.settings/language.settings.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<project>
|
||||||
|
<configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.1510091085" name="Debug">
|
||||||
|
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||||
|
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||||
|
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
|
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
|
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="564395207262711818" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||||
|
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||||
|
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||||
|
</provider>
|
||||||
|
</extension>
|
||||||
|
</configuration>
|
||||||
|
<configuration id="cdt.managedbuild.config.gnu.cross.exe.release.2099010148" name="Release">
|
||||||
|
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||||
|
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||||
|
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
|
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
|
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="564395207262711818" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||||
|
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||||
|
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||||
|
</provider>
|
||||||
|
</extension>
|
||||||
|
</configuration>
|
||||||
|
</project>
|
||||||
8
Makefile
8
Makefile
@@ -1,11 +1,15 @@
|
|||||||
# Digital UNIX 4.0 compilation flags:
|
# Digital UNIX 4.0 compilation flags:
|
||||||
CFLAGS=-std1 -pthread -g -w1 $(DEBUGFLAGS)
|
#CFLAGS=-std1 -pthread -g -w1 $(DEBUGFLAGS)
|
||||||
RTFLAGS=-lrt
|
#RTFLAGS=-lrt
|
||||||
|
|
||||||
# Solaris 2.5 compilation flags:
|
# Solaris 2.5 compilation flags:
|
||||||
#CFLAGS=-D_POSIX_C_SOURCE=199506 -D_REENTRANT -Xa -lpthread -g $(DEBUGFLAGS)
|
#CFLAGS=-D_POSIX_C_SOURCE=199506 -D_REENTRANT -Xa -lpthread -g $(DEBUGFLAGS)
|
||||||
#RTFLAGS=-lposix4
|
#RTFLAGS=-lposix4
|
||||||
|
|
||||||
|
# Linux compilation flags:
|
||||||
|
CFLAGS=-pthread -O3 $(DEBUGFLAGS)
|
||||||
|
RTFLAGS=-lrt
|
||||||
|
|
||||||
SOURCES=alarm.c alarm_cond.c alarm_fork.c alarm_mutex.c \
|
SOURCES=alarm.c alarm_cond.c alarm_fork.c alarm_mutex.c \
|
||||||
alarm_thread.c atfork.c backoff.c \
|
alarm_thread.c atfork.c backoff.c \
|
||||||
barrier_main.c cancel.c cancel_async.c cancel_cleanup\
|
barrier_main.c cancel.c cancel_async.c cancel_cleanup\
|
||||||
|
|||||||
127
alarm_mutex.cpp
Normal file
127
alarm_mutex.cpp
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* alarm_mutex.c
|
||||||
|
*
|
||||||
|
* This is an enhancement to the alarm_thread.c program, which
|
||||||
|
* created an "alarm thread" for each alarm command. This new
|
||||||
|
* version uses a single alarm thread, which reads the next
|
||||||
|
* entry in a list. The main thread places new requests onto the
|
||||||
|
* list, in order of absolute expiration time. The list is
|
||||||
|
* protected by a mutex, and the alarm thread sleeps for at
|
||||||
|
* least 1 second, each iteration, to ensure that the main
|
||||||
|
* thread can lock the mutex to add new work to the list.
|
||||||
|
*/
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The "alarm" structure now contains the time_t (time since the
|
||||||
|
* Epoch, in seconds) for each alarm, so that they can be
|
||||||
|
* sorted. Storing the requested number of seconds would not be
|
||||||
|
* enough, since the "alarm thread" cannot tell how long it has
|
||||||
|
* been on the list.
|
||||||
|
*/
|
||||||
|
struct alarm_tag {
|
||||||
|
int seconds;
|
||||||
|
time_t time; /* seconds from EPOCH */
|
||||||
|
char message[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
using alarm_t = alarm_tag;
|
||||||
|
|
||||||
|
pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
std::list<alarm_t> alarm_list;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The alarm thread's start routine.
|
||||||
|
*/
|
||||||
|
void *alarm_thread(void *arg) {
|
||||||
|
int sleep_time;
|
||||||
|
time_t now;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop forever, processing commands. The alarm thread will
|
||||||
|
* be disintegrated when the process exits.
|
||||||
|
*/
|
||||||
|
while (1) {
|
||||||
|
status = pthread_mutex_lock(&alarm_mutex);
|
||||||
|
if (status != 0) err_abort(status, "Lock mutex");
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
sleep_time = 0;
|
||||||
|
|
||||||
|
for (auto it = alarm_list.begin(); it != alarm_list.end();) {
|
||||||
|
if (it->time <= now) {
|
||||||
|
printf("(%d) %s\n", it->seconds, it->message);
|
||||||
|
it = alarm_list.erase(it);
|
||||||
|
} else {
|
||||||
|
sleep_time = MIN(it->time - now, sleep_time);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlock the mutex before waiting, so that the main
|
||||||
|
* thread can lock it to insert a new alarm request. If
|
||||||
|
* the sleep_time is 0, then call sched_yield, giving
|
||||||
|
* the main thread a chance to run if it has been
|
||||||
|
* readied by user input, without delaying the message
|
||||||
|
* if there's no input.
|
||||||
|
*/
|
||||||
|
status = pthread_mutex_unlock(&alarm_mutex);
|
||||||
|
if (status != 0) err_abort(status, "Unlock mutex");
|
||||||
|
if (sleep_time > 0)
|
||||||
|
sleep(sleep_time);
|
||||||
|
else
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int status;
|
||||||
|
char line[128];
|
||||||
|
pthread_t thread;
|
||||||
|
|
||||||
|
status = pthread_create(&thread, NULL, alarm_thread, NULL);
|
||||||
|
if (status != 0) err_abort(status, "Create alarm thread");
|
||||||
|
while (1) {
|
||||||
|
printf("alarm> ");
|
||||||
|
if (fgets(line, sizeof(line), stdin) == NULL) exit(0);
|
||||||
|
if (strlen(line) <= 1) continue;
|
||||||
|
alarm_t alarm;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse input line into seconds (%d) and a message
|
||||||
|
* (%64[^\n]), consisting of up to 64 characters
|
||||||
|
* separated from the seconds by whitespace.
|
||||||
|
*/
|
||||||
|
if (sscanf(line, "%d %64[^\n]", &alarm.seconds, alarm.message) < 2) {
|
||||||
|
fprintf(stderr, "Bad command\n");
|
||||||
|
} else {
|
||||||
|
alarm.time = time(NULL) + alarm.seconds;
|
||||||
|
|
||||||
|
status = pthread_mutex_lock(&alarm_mutex);
|
||||||
|
if (status != 0) err_abort(status, "Lock mutex");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert the new alarm into the list of alarms.
|
||||||
|
*/
|
||||||
|
alarm_list.push_back(alarm);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("[list: ");
|
||||||
|
for (const auto &iAlarm : alarm_list)
|
||||||
|
printf("%d(%d)[\"%s\"] ", iAlarm.time, iAlarm.time - time(NULL),
|
||||||
|
iAlarm.message);
|
||||||
|
printf("]\n");
|
||||||
|
#endif
|
||||||
|
status = pthread_mutex_unlock(&alarm_mutex);
|
||||||
|
if (status != 0) err_abort(status, "Unlock mutex");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
void *thread_routine (void *arg)
|
void *thread_routine (void *arg)
|
||||||
{
|
{
|
||||||
|
printf("Inside thread %i\n", pthread_self());
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,10 +22,13 @@ main (int argc, char *argv[])
|
|||||||
void *thread_result;
|
void *thread_result;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
printf("Inside thread %i\n", pthread_self());
|
||||||
status = pthread_create (
|
status = pthread_create (
|
||||||
&thread_id, NULL, thread_routine, NULL);
|
&thread_id, NULL, thread_routine, NULL);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
err_abort (status, "Create thread");
|
err_abort (status, "Create thread");
|
||||||
|
sleep(1.0);
|
||||||
|
printf("Main thread created thread %i\n", thread_id);
|
||||||
|
|
||||||
status = pthread_join (thread_id, &thread_result);
|
status = pthread_join (thread_id, &thread_result);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
|
|||||||
268
pipe.cpp
Normal file
268
pipe.cpp
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* pipe.c
|
||||||
|
*
|
||||||
|
* Simple demonstration of a pipeline. main() is a loop that
|
||||||
|
* feeds the pipeline with integer values. Each stage of the
|
||||||
|
* pipeline increases the integer by one before passing it along
|
||||||
|
* to the next. Entering the command "=" reads the pipeline
|
||||||
|
* result. (Notice that too many '=' commands will hang.)
|
||||||
|
*/
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal structure describing a "stage" in the
|
||||||
|
* pipeline. One for each thread, plus a "result
|
||||||
|
* stage" where the final thread can stash the value.
|
||||||
|
*/
|
||||||
|
struct stage_tag {
|
||||||
|
pthread_mutex_t mutex; /* Protect data */
|
||||||
|
pthread_cond_t dataIsAvail; /* Data available */
|
||||||
|
pthread_cond_t threadIsIdle; /* Ready for data */
|
||||||
|
bool isDataAvail; /* Data present */
|
||||||
|
long data; /* Data to process */
|
||||||
|
pthread_t thread; /* Thread for stage */
|
||||||
|
stage_tag *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
using stage_t = stage_tag;
|
||||||
|
|
||||||
|
using StageList = std::list<stage_t>;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* External structure representing the entire
|
||||||
|
* pipeline.
|
||||||
|
*/
|
||||||
|
struct pipe_tag {
|
||||||
|
pthread_mutex_t mutex; /* Mutex to protect pipe */
|
||||||
|
StageList stageList; /* stages list */
|
||||||
|
int nActive; /* Active data elements */
|
||||||
|
};
|
||||||
|
|
||||||
|
using pipe_t = pipe_tag;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal function to send a "message" to the
|
||||||
|
* specified pipe stage. Threads use this to pass
|
||||||
|
* along the modified data item.
|
||||||
|
*/
|
||||||
|
int pipe_send(stage_t &stage, long data) {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = pthread_mutex_lock(&stage.mutex);
|
||||||
|
if (status != 0) return status;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there's data in the pipe stage, wait for it
|
||||||
|
* to be consumed.
|
||||||
|
*/
|
||||||
|
while (stage.isDataAvail) {
|
||||||
|
status = pthread_cond_wait(&stage.threadIsIdle, &stage.mutex);
|
||||||
|
if (status != 0) {
|
||||||
|
pthread_mutex_unlock(&stage.mutex);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send the new data
|
||||||
|
*/
|
||||||
|
stage.data = data;
|
||||||
|
stage.isDataAvail = true;
|
||||||
|
|
||||||
|
status = pthread_cond_signal(&stage.dataIsAvail);
|
||||||
|
if (status != 0) {
|
||||||
|
pthread_mutex_unlock(&stage.mutex);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = pthread_mutex_unlock(&stage.mutex);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The thread start routine for pipe stage threads.
|
||||||
|
* Each will wait for a data item passed from the
|
||||||
|
* caller or the previous stage, modify the data
|
||||||
|
* and pass it along to the next (or final) stage.
|
||||||
|
*/
|
||||||
|
void *pipe_stage(void *arg) {
|
||||||
|
stage_t &stage = *(stage_t *)arg;
|
||||||
|
stage_t &nextStage = *stage.next;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = pthread_mutex_lock(&stage.mutex);
|
||||||
|
if (status != 0) err_abort(status, "Lock pipe stage");
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
while (!stage.isDataAvail) {
|
||||||
|
status = pthread_cond_wait(&stage.dataIsAvail, &stage.mutex);
|
||||||
|
if (status != 0) err_abort(status, "Wait for previous stage");
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe_send(nextStage, stage.data + 1);
|
||||||
|
|
||||||
|
stage.isDataAvail = false;
|
||||||
|
|
||||||
|
status = pthread_cond_signal(&stage.threadIsIdle);
|
||||||
|
if (status != 0) err_abort(status, "Wake next stage");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notice that the routine never unlocks the stage->mutex.
|
||||||
|
* The call to pthread_cond_wait implicitly unlocks the
|
||||||
|
* mutex while the thread is waiting, allowing other threads
|
||||||
|
* to make progress. Because the loop never terminates, this
|
||||||
|
* function has no need to unlock the mutex explicitly.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* External interface to create a pipeline. All the
|
||||||
|
* data is initialized and the threads created. They'll
|
||||||
|
* wait for data.
|
||||||
|
*/
|
||||||
|
int pipe_create(pipe_t &pipe, size_t nStages) {
|
||||||
|
int status = pthread_mutex_init(&pipe.mutex, NULL);
|
||||||
|
if (status != 0) err_abort(status, "Init pipe mutex");
|
||||||
|
|
||||||
|
pipe.stageList.resize(nStages);
|
||||||
|
pipe.nActive = 0;
|
||||||
|
|
||||||
|
for (auto &iStage : pipe.stageList) {
|
||||||
|
status = pthread_mutex_init(&iStage.mutex, NULL);
|
||||||
|
if (status != 0) err_abort(status, "Init stage mutex");
|
||||||
|
status = pthread_cond_init(&iStage.dataIsAvail, NULL);
|
||||||
|
if (status != 0) err_abort(status, "Init dataIsAvail condition");
|
||||||
|
status = pthread_cond_init(&iStage.threadIsIdle, NULL);
|
||||||
|
if (status != 0) err_abort(status, "Init threadIsIdle condition");
|
||||||
|
iStage.isDataAvail = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the threads for the pipe stages only after all
|
||||||
|
* the data is initialized (including all links). Note
|
||||||
|
* that the last stage doesn't get a thread, it's just
|
||||||
|
* a receptacle for the final pipeline value.
|
||||||
|
*
|
||||||
|
* At this point, proper cleanup on an error would take up
|
||||||
|
* more space than worthwhile in a "simple example", so
|
||||||
|
* instead of cancelling and detaching all the threads
|
||||||
|
* already created, plus the synchronization object and
|
||||||
|
* memory cleanup done for earlier errors, it will simply
|
||||||
|
* abort.
|
||||||
|
*/
|
||||||
|
for (auto it = pipe.stageList.begin(), ite = --pipe.stageList.end();
|
||||||
|
it != ite;) {
|
||||||
|
auto iit = it++;
|
||||||
|
iit->next = &(*it);
|
||||||
|
|
||||||
|
status = pthread_create(&iit->thread, NULL, pipe_stage, (void *)&*iit);
|
||||||
|
if (status != 0) err_abort(status, "Create pipe stage");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Collect the result of the pipeline. Wait for a
|
||||||
|
* result if the pipeline hasn't produced one.
|
||||||
|
*/
|
||||||
|
int pipe_result(pipe_t &pipe) {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = pthread_mutex_lock(&pipe.mutex);
|
||||||
|
if (status != 0) err_abort(status, "Lock pipe mutex");
|
||||||
|
|
||||||
|
bool isEmpty = false;
|
||||||
|
if (pipe.nActive <= 0)
|
||||||
|
isEmpty = true;
|
||||||
|
else
|
||||||
|
pipe.nActive--;
|
||||||
|
|
||||||
|
status = pthread_mutex_unlock(&pipe.mutex);
|
||||||
|
if (status != 0) err_abort(status, "Unlock pipe mutex");
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
printf("Pipe is empty\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &tail = pipe.stageList.back();
|
||||||
|
|
||||||
|
status = pthread_mutex_lock(&tail.mutex);
|
||||||
|
if (status != 0) err_abort(status, "Lock pipe tail mutex");
|
||||||
|
|
||||||
|
while (!tail.isDataAvail) {
|
||||||
|
pthread_cond_wait(&tail.dataIsAvail, &tail.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
long result = tail.data;
|
||||||
|
tail.isDataAvail = false;
|
||||||
|
|
||||||
|
status = pthread_cond_signal(&tail.threadIsIdle);
|
||||||
|
if (status != 0) err_abort(status, "Signal pipe tail threadIsIdle");
|
||||||
|
|
||||||
|
status = pthread_mutex_unlock(&tail.mutex);
|
||||||
|
if (status != 0) err_abort(status, "Unlock pipe tail mutex");
|
||||||
|
|
||||||
|
printf("Result is %ld\n", result);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* External interface to start a pipeline by passing
|
||||||
|
* data to the first stage. The routine returns while
|
||||||
|
* the pipeline processes in parallel. Call the
|
||||||
|
* pipe_result return to collect the final stage values
|
||||||
|
* (note that the pipe will stall when each stage fills,
|
||||||
|
* until the result is collected).
|
||||||
|
*/
|
||||||
|
void pipe_start(pipe_t &pipe, long value) {
|
||||||
|
int status = pthread_mutex_lock(&pipe.mutex);
|
||||||
|
if (status != 0) err_abort(status, "Lock pipe mutex");
|
||||||
|
|
||||||
|
if (pipe.nActive > pipe.stageList.size() - 1) {
|
||||||
|
status = pthread_mutex_unlock(&pipe.mutex);
|
||||||
|
pipe_result(pipe);
|
||||||
|
status = pthread_mutex_lock(&pipe.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe.nActive++;
|
||||||
|
|
||||||
|
status = pthread_mutex_unlock(&pipe.mutex);
|
||||||
|
if (status != 0) err_abort(status, "Unlock pipe mutex");
|
||||||
|
|
||||||
|
pipe_send(pipe.stageList.front(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The main program to "drive" the pipeline...
|
||||||
|
*/
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
pipe_t my_pipe;
|
||||||
|
pipe_create(my_pipe, 2);
|
||||||
|
|
||||||
|
printf("Enter integer values, or \"=\" for next result\n");
|
||||||
|
|
||||||
|
char line[128];
|
||||||
|
while (1) {
|
||||||
|
printf("Data> ");
|
||||||
|
if (fgets(line, sizeof(line), stdin) == NULL) exit(0);
|
||||||
|
printf(line);
|
||||||
|
if (strlen(line) <= 1) continue;
|
||||||
|
if (strlen(line) <= 2 && line[0] == '=') {
|
||||||
|
pipe_result(my_pipe);
|
||||||
|
} else {
|
||||||
|
long value;
|
||||||
|
if (sscanf(line, "%ld", &value) < 1)
|
||||||
|
fprintf(stderr, "Enter an integer value\n");
|
||||||
|
else
|
||||||
|
pipe_start(my_pipe, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
trylock.c
53
trylock.c
@@ -24,8 +24,7 @@ time_t end_time;
|
|||||||
* Thread start routine that repeatedly locks a mutex and
|
* Thread start routine that repeatedly locks a mutex and
|
||||||
* increments a counter.
|
* increments a counter.
|
||||||
*/
|
*/
|
||||||
void *counter_thread (void *arg)
|
void *counter_thread(void *arg) {
|
||||||
{
|
|
||||||
int status;
|
int status;
|
||||||
int spin;
|
int spin;
|
||||||
|
|
||||||
@@ -35,16 +34,13 @@ void *counter_thread (void *arg)
|
|||||||
* sleeps for another second with the mutex locked, to give
|
* sleeps for another second with the mutex locked, to give
|
||||||
* monitor_thread a reasonable chance of running.
|
* monitor_thread a reasonable chance of running.
|
||||||
*/
|
*/
|
||||||
while (time (NULL) < end_time)
|
while (time(NULL) < end_time) {
|
||||||
{
|
|
||||||
status = pthread_mutex_lock(&mutex);
|
status = pthread_mutex_lock(&mutex);
|
||||||
if (status != 0)
|
if (status != 0) err_abort(status, "Lock mutex");
|
||||||
err_abort (status, "Lock mutex");
|
for (spin = 0; spin < SPIN; spin++) counter++;
|
||||||
for (spin = 0; spin < SPIN; spin++)
|
sleep(4);
|
||||||
counter++;
|
|
||||||
status = pthread_mutex_unlock(&mutex);
|
status = pthread_mutex_unlock(&mutex);
|
||||||
if (status != 0)
|
if (status != 0) err_abort(status, "Unlock mutex");
|
||||||
err_abort (status, "Unlock mutex");
|
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
printf("Counter is %#lx\n", counter);
|
printf("Counter is %#lx\n", counter);
|
||||||
@@ -56,28 +52,22 @@ void *counter_thread (void *arg)
|
|||||||
* seconds, try to lock the mutex and read the counter. If the
|
* seconds, try to lock the mutex and read the counter. If the
|
||||||
* trylock fails, skip this cycle.
|
* trylock fails, skip this cycle.
|
||||||
*/
|
*/
|
||||||
void *monitor_thread (void *arg)
|
void *monitor_thread(void *arg) {
|
||||||
{
|
|
||||||
int status;
|
int status;
|
||||||
int misses = 0;
|
int misses = 0;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop until end_time, checking the counter every 3
|
* Loop until end_time, checking the counter every 3
|
||||||
* seconds.
|
* seconds.
|
||||||
*/
|
*/
|
||||||
while (time (NULL) < end_time)
|
while (time(NULL) < end_time) {
|
||||||
{
|
|
||||||
sleep(3);
|
sleep(3);
|
||||||
status = pthread_mutex_trylock(&mutex);
|
status = pthread_mutex_trylock(&mutex);
|
||||||
if (status != EBUSY)
|
if (status != EBUSY) {
|
||||||
{
|
if (status != 0) err_abort(status, "Trylock mutex");
|
||||||
if (status != 0)
|
|
||||||
err_abort (status, "Trylock mutex");
|
|
||||||
printf("Counter is %ld\n", counter / SPIN);
|
printf("Counter is %ld\n", counter / SPIN);
|
||||||
status = pthread_mutex_unlock(&mutex);
|
status = pthread_mutex_unlock(&mutex);
|
||||||
if (status != 0)
|
if (status != 0) err_abort(status, "Unlock mutex");
|
||||||
err_abort (status, "Unlock mutex");
|
|
||||||
} else
|
} else
|
||||||
misses++; /* Count "misses" on the lock */
|
misses++; /* Count "misses" on the lock */
|
||||||
}
|
}
|
||||||
@@ -85,8 +75,7 @@ void *monitor_thread (void *arg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char *argv[])
|
int main(int argc, char *argv[]) {
|
||||||
{
|
|
||||||
int status;
|
int status;
|
||||||
pthread_t counter_thread_id;
|
pthread_t counter_thread_id;
|
||||||
pthread_t monitor_thread_id;
|
pthread_t monitor_thread_id;
|
||||||
@@ -102,19 +91,13 @@ int main (int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
end_time = time(NULL) + 60; /* Run for 1 minute */
|
end_time = time(NULL) + 60; /* Run for 1 minute */
|
||||||
status = pthread_create (
|
status = pthread_create(&counter_thread_id, NULL, counter_thread, NULL);
|
||||||
&counter_thread_id, NULL, counter_thread, NULL);
|
if (status != 0) err_abort(status, "Create counter thread");
|
||||||
if (status != 0)
|
status = pthread_create(&monitor_thread_id, NULL, monitor_thread, NULL);
|
||||||
err_abort (status, "Create counter thread");
|
if (status != 0) err_abort(status, "Create monitor thread");
|
||||||
status = pthread_create (
|
|
||||||
&monitor_thread_id, NULL, monitor_thread, NULL);
|
|
||||||
if (status != 0)
|
|
||||||
err_abort (status, "Create monitor thread");
|
|
||||||
status = pthread_join(counter_thread_id, NULL);
|
status = pthread_join(counter_thread_id, NULL);
|
||||||
if (status != 0)
|
if (status != 0) err_abort(status, "Join counter thread");
|
||||||
err_abort (status, "Join counter thread");
|
|
||||||
status = pthread_join(monitor_thread_id, NULL);
|
status = pthread_join(monitor_thread_id, NULL);
|
||||||
if (status != 0)
|
if (status != 0) err_abort(status, "Join monitor thread");
|
||||||
err_abort (status, "Join monitor thread");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user