Adding cpp mocks

This commit is contained in:
Bassem Girgis
2018-10-17 11:12:34 -05:00
parent a5ec64177d
commit 63027dd857
8 changed files with 623 additions and 80 deletions

106
.cproject Normal file
View 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
View 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>

View 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 &quot;${INPUTS}&quot;" 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 &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
</configuration>
</project>

View File

@@ -1,11 +1,15 @@
# Digital UNIX 4.0 compilation flags:
CFLAGS=-std1 -pthread -g -w1 $(DEBUGFLAGS)
RTFLAGS=-lrt
#CFLAGS=-std1 -pthread -g -w1 $(DEBUGFLAGS)
#RTFLAGS=-lrt
# Solaris 2.5 compilation flags:
#CFLAGS=-D_POSIX_C_SOURCE=199506 -D_REENTRANT -Xa -lpthread -g $(DEBUGFLAGS)
#RTFLAGS=-lposix4
# Linux compilation flags:
CFLAGS=-pthread -O3 $(DEBUGFLAGS)
RTFLAGS=-lrt
SOURCES=alarm.c alarm_cond.c alarm_fork.c alarm_mutex.c \
alarm_thread.c atfork.c backoff.c \
barrier_main.c cancel.c cancel_async.c cancel_cleanup\

127
alarm_mutex.cpp Normal file
View 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");
}
}
}

View File

@@ -12,6 +12,7 @@
*/
void *thread_routine (void *arg)
{
printf("Inside thread %i\n", pthread_self());
return arg;
}
@@ -21,10 +22,13 @@ main (int argc, char *argv[])
void *thread_result;
int status;
printf("Inside thread %i\n", pthread_self());
status = pthread_create (
&thread_id, NULL, thread_routine, NULL);
if (status != 0)
err_abort (status, "Create thread");
sleep(1.0);
printf("Main thread created thread %i\n", thread_id);
status = pthread_join (thread_id, &thread_result);
if (status != 0)

268
pipe.cpp Normal file
View 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);
}
}
}

View File

@@ -24,8 +24,7 @@ time_t end_time;
* Thread start routine that repeatedly locks a mutex and
* increments a counter.
*/
void *counter_thread (void *arg)
{
void *counter_thread(void *arg) {
int status;
int spin;
@@ -35,16 +34,13 @@ void *counter_thread (void *arg)
* sleeps for another second with the mutex locked, to give
* monitor_thread a reasonable chance of running.
*/
while (time (NULL) < end_time)
{
while (time(NULL) < end_time) {
status = pthread_mutex_lock(&mutex);
if (status != 0)
err_abort (status, "Lock mutex");
for (spin = 0; spin < SPIN; spin++)
counter++;
if (status != 0) err_abort(status, "Lock mutex");
for (spin = 0; spin < SPIN; spin++) counter++;
sleep(4);
status = pthread_mutex_unlock(&mutex);
if (status != 0)
err_abort (status, "Unlock mutex");
if (status != 0) err_abort(status, "Unlock mutex");
sleep(1);
}
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
* trylock fails, skip this cycle.
*/
void *monitor_thread (void *arg)
{
void *monitor_thread(void *arg) {
int status;
int misses = 0;
/*
* Loop until end_time, checking the counter every 3
* seconds.
*/
while (time (NULL) < end_time)
{
while (time(NULL) < end_time) {
sleep(3);
status = pthread_mutex_trylock(&mutex);
if (status != EBUSY)
{
if (status != 0)
err_abort (status, "Trylock mutex");
if (status != EBUSY) {
if (status != 0) err_abort(status, "Trylock mutex");
printf("Counter is %ld\n", counter / SPIN);
status = pthread_mutex_unlock(&mutex);
if (status != 0)
err_abort (status, "Unlock mutex");
if (status != 0) err_abort(status, "Unlock mutex");
} else
misses++; /* Count "misses" on the lock */
}
@@ -85,8 +75,7 @@ void *monitor_thread (void *arg)
return NULL;
}
int main (int argc, char *argv[])
{
int main(int argc, char *argv[]) {
int status;
pthread_t counter_thread_id;
pthread_t monitor_thread_id;
@@ -102,19 +91,13 @@ int main (int argc, char *argv[])
#endif
end_time = time(NULL) + 60; /* Run for 1 minute */
status = pthread_create (
&counter_thread_id, NULL, counter_thread, NULL);
if (status != 0)
err_abort (status, "Create counter thread");
status = pthread_create (
&monitor_thread_id, NULL, monitor_thread, NULL);
if (status != 0)
err_abort (status, "Create monitor thread");
status = pthread_create(&counter_thread_id, NULL, counter_thread, NULL);
if (status != 0) err_abort(status, "Create counter 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);
if (status != 0)
err_abort (status, "Join counter thread");
if (status != 0) err_abort(status, "Join counter thread");
status = pthread_join(monitor_thread_id, NULL);
if (status != 0)
err_abort (status, "Join monitor thread");
if (status != 0) err_abort(status, "Join monitor thread");
return 0;
}