I am working on a reader/writer program where there is one writer to n readers. I am having an issue where if multiple readers are in, like the screenshot posted below, then the entire message from shared memory isnt displayed.
Output:
Enter a Message: Test
Reader1: Test
Reader2: Test
Writer: test test
Reader1: test
Reader2: test test
Writer:
Readers:
I have tried to add a count variable because I assume that the writers turn is being flagged before all readers have the ability to print and its making the writer then exit the nested while() in the writer and stop the readers from printing.
Any suggestions on to make the readers both print, whether it be a flag or some sort of count? Attached below are also screenshots of the writer and reader loops.
Reader:
int main() {
DataShared data;
data.turn = 0;
signal(SIGINT, sigHandler);
//generates key
key = ftok("mkey",65);
//returns an identifier in mId
if ((mId = shmget(key, SIZE, IPC_CREAT|S_IRUSR|S_IWUSR)) < 0){
perror("shared memory error");
exit(1);
}
// shmat to attach to shared memory
if((mPtr = shmat(mId, 0, 0)) == (void*) -1) {
perror("Can't attach\n");
exit(1);
}
while(1) {
// request critical section
while(!data.turn && data.count == 0) {
//not time for the reader, check if token is changed.
memcpy(&data, mPtr, sizeof(DataShared));
}
data.count++;
// enter critical section
usleep(1);
fprintf(stderr, "Read from memory: %s\n", data.message);
usleep(1);
// leave critical section
data.count--;
while(data.count > 0){
;
}
data.turn = 0;
memcpy(mPtr, &data, sizeof(DataShared));
};
return 0;
}
Writer:
int main() {
DataShared data;
data.turn = 0;
data.count = 0;
signal(SIGINT, sigHandler);
key = ftok("mkey",65);
if((shmId = shmget(key, SIZE, IPC_CREAT|S_IRUSR|S_IWUSR)) < 0 ) {
perror("Error creating shared memory\n");
exit(1);
}
if((shmPtr = shmat(shmId, 0, 0)) == (void*) -1) {
perror("Can't attach\n");
exit(1);
}
while(1) {
while (data.turn) {
memcpy(&data, shmPtr, sizeof(DataShared));
}
// enter critical section
printf("Enter a message: \n" );
fgets(data.message, 1024, stdin);
// leave critical section
printf("Message written to memory: %s\n", data.message);
data.turn = 1;
memcpy(shmPtr, &data, sizeof(DataShared));
};
return 0;
}
This may not be the explanation of your observation, but what you do is fishy.
You have multiple processes and the OS schedules each process.
First, there is no guarantee that all readers will read the message. It is very well possible that one reader finishes, sets the flag to 0 and copies the data back to shared memory before another reader had a chance to read the data.
Then your data.count. It starts with the local variable data of the writer. there you do not initialize data.count so it has an indeterminate value. In the readers you set it to 0 but it will be overwritten with the value from shared memory (the indeterminate value). You do a ++, later a -- and then wait for it to become 0. How would that ever become zero? That reader could wait forever.
I want to use Windows Semaphores to add synchronization to a Windows File Mapping. So, one process creates the file mapping and another (perhaps multiple other processes) can come in and access the data that is shared. Can anyone give a suggestion as to how this can be done. I have done the following:
In the process that creates the file mapping, I have used CreateSemaphore and specified a name. In another process that attempts to access the data, I use OpenSemaphore to get a handle to the created sempahore, then I call WaitForSingleObject, I then switch on this value, and if its WAIT_OBJECT0, I perform the work, and finally calling ReleaseSemaphore once the work is done.
I am doing this in C, using a JNI shared library.
The problem is that it simply goes into the default case. Is there anything else that I should do, or am I missing something?
I'm pretty new to how Windows sems work, and I cannot find a concrete example
of how they work between multiple processes (no threads). If anyone can give any suggestions, It would be much appreciated.
Here is some code:
Create the file mapping
// create the semaphore here
semaphore = CreateSemaphore(
NULL,
10,
10,
SEMAPHORE_NAME
);
// some semaphore error checking
if (semaphore == NULL) {
printf("Error occured creating semaphore %d\n", GetLastError());
return -1;
}
//create mapping object
mappedFileHandle = CreateFileMapping (
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
BUFFER_SIZE,
MEMORY_MAPPING_NAME
);
if (mappedFileHandle == NULL) {
printf("Error creating a mapped file: %d", GetLastError());
return -1;
}
// map view of a file into address space of a calling process
buffer = (LPCTSTR) MapViewOfFile (
mappedFileHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
BUFFER_SIZE
);
if (buffer == NULL) {
printf("Could not map view");
CloseHandle(mappedFileHandle);
return -1;
}
CopyMemory(buffer, str, (_tcslen(str) * sizeof(TCHAR))); // problem!!
UnmapViewOfFile(buffer);
CloseHandle(mappedFileHandle);
// CloseHandle(semaphore);
Process code that gets the data
// try open the semahore
semaphore = OpenSemaphore (
SEMAPHORE_ALL_ACCESS,
NULL,
SEMAPHORE_NAME
);
// some error checking
if (semaphore == NULL) {
printf("Could not open semaphore %d\n", GetLastError());
return -1;
}
waitResult = WaitForSingleObject(
semaphore,
-1 // block
);
// try to open the file mapping -- SHOULD BE DONE ATOMICALLY
// ======================================================================
switch (waitResult) {
case WAIT_OBJECT_0:
printf("Got in wait_result0");
mappedFileHandle = OpenFileMapping (
FILE_MAP_ALL_ACCESS,
FALSE,
MEMORY_MAPPING_NAME
);
if (mappedFileHandle == NULL) {
printf("Could not open file mapping");
return errorForJavaProgram;
}
// read data here, must be a critical region
buffer = (LPTSTR) MapViewOfFile(
mappedFileHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
BUFFER_SIZE
);
if (buffer == NULL) {
printf("Could not map view");
CloseHandle(mappedFileHandle);
return errorForJavaProgram;
}
message = (*env)->NewStringUTF(env, buffer);
if (!ReleaseSemaphore(semaphore, 1, NULL)) {
printf("An error occured releasing the semaphore: %d\n", GetLastError());
return -1;
}
default:
printf("Got to default \n");
} //switch
Your switch statement is subject to fall through. For one of the many discussions that can be found here on Stack Overflow, see Does case-switch work like this?.
Your code executes the WAIT_OBJECT_0 and then simply continues to the default case. You need to add a break or a return at the very end of the WAIT_OBJECT_0 case.
I stumbled upon a tutorial about dll injection in c. When I run my code, it gives me a Debug Assertion Failed error when I use the CreateRemoteThread() function in my code.
I use Visual Studio Express 2015 on Windows 10
The Error:
#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
char* buffer = "C:\\inject2.dll";
//Get the process handle passing in the process ID
int procID = 9872;
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
if (process == NULL) {
printf("Error: the specified process couldn't be found\n");
}
//Get the address of the LoadLibrary function
LPVOID addr = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
if (addr == NULL) {
printf("Error: the LoadLibraryA function was not found inside kernel32.dll library.\n");
}
//Allocate new memory region inside the process's address space
LPVOID arg = (LPVOID)VirtualAllocEx(process, NULL, strlen(buffer), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (arg == NULL)
{
printf("Error: the memory could not be allocated inside the chosen process.\n");
}
//Write the argument to LoadLibraryA to the process's newly allocated memory region
int n = WriteProcessMemory(process, arg, buffer, strlen(buffer), NULL);
if (n == 0) {
printf("Error: there were not bytes written to the process's address space.\n");
}
//Inject our DLL into the process's address space
HANDLE threadID = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)addr, arg, NULL, NULL);
if (threadID == NULL)
{
printf("Error: the remote thread could not be created.\n");
}
else
{
printf("Success: the remote thread was succesfully created.\n");
}
//Close the handle to the process because we have already injected the DLL
CloseHandle(process);
getchar();
return 0;
}
If you're using the DLL from the link you supplied, it's probably failing because it's attempting to write to the root of the system drive ("C:\\temp.txt",). Change this path to something your target process can write to.
In the C language using the Windows API, how can I get the output of a process when I have its process information?
I have code like this:
STARTUPINFO si1;
ZeroMemory(&si1,sizeof(si1));
PROCESS_INFORMATION pi1;
ZeroMemory(&pi1,sizeof(pi1));
BOOL bRes1=CreateProcess(_T("C:\\User\\asd.exe"),cmd_line1,NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL, &si1,&pi1);
and the process asd.exe prints a certain output, I want to get it to my process(the one i used the code above in).
This answer is probably a bit longer than you expected, but that's how the Windows API is sometimes. In any case, even though this takes more code than it initially seems like it should need, this at least provides a fairly clean, easy to use interface for programs that want to do things like this. The code is commented fairly liberally, explaining not only how to use the function it provides, but also how it's doing most of what it does, and what Windows requires if you decide to write code based on this instead of using it directly.
I should also point out that this is some fairly old code. It works well enough that I haven't had any reason to rewrite it, but if I was doing it again today, I'm pretty sure I'd do it quite a bit differently (for one thing, I'd undoubtedly use C++ instead of straight C, as I did here).
This does also contain some tidbits of code that are frequently useful for completely unrelated purposes (e.g., I've used system_error quite a few places -- it's Windows-only, but really incidental to spawning a child process).
Anyway, we'll start with spawn.h, which defines the interface to the code:
#ifndef SPAWN_H_INCLUDED_
#define SPAWN_H_INCLUDED_
// What to do if you ask to create a file and it already exists.
// We can fail to create it, overwrite the existing content, or append the
// new content to the existing content.
enum { FAIL, OVERWRITE, APPEND };
// This just specifies the type of a thread procedure to use to handle a stream
// to/from the child, if you decided to do that.
//
typedef unsigned long (__stdcall *ThrdProc)(void *);
// stream_info is the real core of the code. It's what lets you specify how
// to deal with a particular stream. When you call CreateDetchedProcess,
// you need to pass the address of an array of three stream_info objects
// that specify the handling for the child's standard input, standard
// output, and standard error streams respectively. If you specify a
// filename, that stream will be connected to the named file. If you set
// filename to NULL, you can instead specify a procedure that will be
// started in a thread that will provide data for that stream, or process
// the data coming from that stream. Toward the bottom of spawn.c there are
// a couple of sample handlers, one that processes standard error, and the
// other that processes standard output from a spawned child process.
//
typedef struct {
char *filename;
ThrdProc handler;
HANDLE handle;
} stream_info;
// Once you've filled in your stream_info structures, spawning the child is
// pretty easy: just pass the name of the executable for the child, and the
// address of the stream_info array. This handles most of the usual things:
// if you don't specify an extension for the file, it'll search for it with
// extensions of `.com", ".exe", ".cmd", and ".bat" in the current
// directory, and then in any directory specified by the PATH environment
// variable. It'll open/create any files you've specified in the
// stream_info structures, and create pipes for any streams that are to be
// directed to the parent, and start up threads to run any stream handlers
// specified.
//
HANDLE CreateDetachedProcess(char const *name, stream_info *streams);
#endif
Then the implementation of CreateDetachedProcess (along with some test/demo code):
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <ctype.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include "spawn.h"
static void system_error(char const *name) {
// A function to retrieve, format, and print out a message from the
// last error. The `name' that's passed should be in the form of a
// present tense noun (phrase) such as "opening file".
//
char *ptr = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
GetLastError(),
0,
(char *)&ptr,
1024,
NULL);
fprintf(stderr, "%s\n", ptr);
LocalFree(ptr);
}
static void InitializeInheritableSA(SECURITY_ATTRIBUTES *sa) {
sa->nLength = sizeof *sa;
sa->bInheritHandle = TRUE;
sa->lpSecurityDescriptor = NULL;
}
static HANDLE OpenInheritableFile(char const *name) {
SECURITY_ATTRIBUTES sa;
HANDLE retval;
InitializeInheritableSA(&sa);
retval = CreateFile(
name,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == retval) {
char buffer[100];
sprintf(buffer, "opening file %s", name);
system_error(buffer);
return retval;
}
}
static HANDLE CreateInheritableFile(char const *name, int mode) {
SECURITY_ATTRIBUTES sa;
HANDLE retval;
DWORD FSmode = mode ? OPEN_ALWAYS : CREATE_NEW;
InitializeInheritableSA(&sa);
retval = CreateFile(
name,
GENERIC_WRITE,
FILE_SHARE_READ,
&sa,
FSmode,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == retval) {
char buffer[100];
sprintf(buffer, "creating file %s", name);
system_error(buffer);
return retval;
}
if ( mode == APPEND )
SetFilePointer(retval, 0, 0, FILE_END);
}
enum inheritance { inherit_read = 1, inherit_write = 2 };
static BOOL CreateInheritablePipe(HANDLE *read, HANDLE *write, int inheritance) {
SECURITY_ATTRIBUTES sa;
InitializeInheritableSA(&sa);
if ( !CreatePipe(read, write, &sa, 0)) {
system_error("Creating pipe");
return FALSE;
}
if (!inheritance & inherit_read)
DuplicateHandle(
GetCurrentProcess(),
*read,
GetCurrentProcess(),
NULL,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (!inheritance & inherit_write)
DuplicateHandle(
GetCurrentProcess(),
*write,
GetCurrentProcess(),
NULL,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
return TRUE;
}
static BOOL find_image(char const *name, char *buffer) {
// Try to find an image file named by the user.
// First search for the exact file name in the current
// directory. If that's found, look for same base name
// with ".com", ".exe" and ".bat" appended, in that order.
// If we can't find it in the current directory, repeat
// the entire process on directories specified in the
// PATH environment variable.
//
#define elements(array) (sizeof(array)/sizeof(array[0]))
static char *extensions[] = {".com", ".exe", ".bat", ".cmd"};
int i;
char temp[FILENAME_MAX];
if (-1 != access(name, 0)) {
strcpy(buffer, name);
return TRUE;
}
for (i=0; i<elements(extensions); i++) {
strcpy(temp, name);
strcat(temp, extensions[i]);
if ( -1 != access(temp, 0)) {
strcpy(buffer, temp);
return TRUE;
}
}
_searchenv(name, "PATH", buffer);
if ( buffer[0] != '\0')
return TRUE;
for ( i=0; i<elements(extensions); i++) {
strcpy(temp, name);
strcat(temp, extensions[i]);
_searchenv(temp, "PATH", buffer);
if ( buffer[0] != '\0')
return TRUE;
}
return FALSE;
}
static HANDLE DetachProcess(char const *name, HANDLE const *streams) {
STARTUPINFO s;
PROCESS_INFORMATION p;
char buffer[FILENAME_MAX];
memset(&s, 0, sizeof s);
s.cb = sizeof(s);
s.dwFlags = STARTF_USESTDHANDLES;
s.hStdInput = streams[0];
s.hStdOutput = streams[1];
s.hStdError = streams[2];
if ( !find_image(name, buffer)) {
system_error("Finding Image file");
return INVALID_HANDLE_VALUE;
}
// Since we've redirected the standard input, output and error handles
// of the child process, we create it without a console of its own.
// (That's the `DETACHED_PROCESS' part of the call.) Other
// possibilities include passing 0 so the child inherits our console,
// or passing CREATE_NEW_CONSOLE so the child gets a console of its
// own.
//
if (!CreateProcess(
NULL,
buffer, NULL, NULL,
TRUE,
DETACHED_PROCESS,
NULL, NULL,
&s,
&p))
{
system_error("Spawning program");
return INVALID_HANDLE_VALUE;
}
// Since we don't need the handle to the child's thread, close it to
// save some resources.
CloseHandle(p.hThread);
return p.hProcess;
}
static HANDLE StartStreamHandler(ThrdProc proc, HANDLE stream) {
DWORD ignore;
return CreateThread(
NULL,
0,
proc,
(void *)stream,
0,
&ignore);
}
HANDLE CreateDetachedProcess(char const *name, stream_info *streams) {
// This Creates a detached process.
// First parameter: name of process to start.
// Second parameter: names of files to redirect the standard input, output and error
// streams of the child to (in that order.) Any file name that is NULL will be
// redirected to an anonymous pipe connected to the parent.
// Third Parameter: handles of the anonymous pipe(s) for the standard input, output
// and/or error streams of the new child process.
//
// Return value: a handle to the newly created process.
//
HANDLE child_handles[3];
HANDLE process;
int i;
// First handle the child's standard input. This is separate from the
// standard output and standard error because it's going the opposite
// direction. Basically, we create either a handle to a file the child
// will use, or else a pipe so the child can communicate with us.
//
if ( streams[0].filename != NULL ) {
streams[0].handle = NULL;
child_handles[0] = OpenInheritableFile(streams[0].filename);
}
else
CreateInheritablePipe(child_handles, &(streams[0].handle), inherit_read);
// Now handle the child's standard output and standard error streams. These
// are separate from the code above simply because they go in the opposite
// direction.
//
for ( i=1; i<3; i++)
if ( streams[i].filename != NULL) {
streams[i].handle = NULL;
child_handles[i] = CreateInheritableFile(streams[i].filename, APPEND);
}
else
CreateInheritablePipe(&(streams[i].handle), child_handles+i, inherit_write);
// Now that we've set up the pipes and/or files the child's going to use,
// we're ready to actually start up the child process:
process = DetachProcess(name, child_handles);
if (INVALID_HANDLE_VALUE == process)
return process;
// Now that we've started the child, we close our handles to its ends of the pipes.
// If one or more of these happens to a handle to a file instead, it doesn't really
// need to be closed, but it doesn't hurt either. However, with the child's standard
// output and standard error streams, it's CRUCIAL to close our handles if either is a
// handle to a pipe. The system detects the end of data on a pipe when ALL handles to
// the write end of the pipe are closed -- if we still have an open handle to the
// write end of one of these pipes, we won't be able to detect when the child is done
// writing to the pipe.
//
for ( i=0; i<3; i++) {
CloseHandle(child_handles[i]);
if ( streams[i].handler )
streams[i].handle =
StartStreamHandler(streams[i].handler, streams[i].handle);
}
return process;
}
#ifdef TEST
#define buf_size 256
unsigned long __stdcall handle_error(void *pipe) {
// The control (and only) function for a thread handling the standard
// error from the child process. We'll handle it by displaying a
// message box each time we receive data on the standard error stream.
//
char buffer[buf_size];
HANDLE child_error_rd = (HANDLE)pipe;
unsigned bytes;
while (ERROR_BROKEN_PIPE != GetLastError() &&
ReadFile(child_error_rd, buffer, 256, &bytes, NULL))
{
buffer[bytes+1] = '\0';
MessageBox(NULL, buffer, "Error", MB_OK);
}
return 0;
}
unsigned long __stdcall handle_output(void *pipe) {
// A similar thread function to handle standard output from the child
// process. Nothing special is done with the output - it's simply
// displayed in our console. However, just for fun it opens a C high-
// level FILE * for the handle, and uses fgets to read it. As
// expected, fgets detects the broken pipe as the end of the file.
//
char buffer[buf_size];
int handle;
FILE *file;
handle = _open_osfhandle((long)pipe, _O_RDONLY | _O_BINARY);
file = _fdopen(handle, "r");
if ( NULL == file )
return 1;
while ( fgets(buffer, buf_size, file))
printf("%s", buffer);
return 0;
}
int main(int argc, char **argv) {
stream_info streams[3];
HANDLE handles[3];
int i;
if ( argc < 3 ) {
fputs("Usage: spawn prog datafile"
"\nwhich will spawn `prog' with its standard input set to"
"\nread from `datafile'. Then `prog's standard output"
"\nwill be captured and printed. If `prog' writes to its"
"\nstandard error, that output will be displayed in a"
"\nMessageBox.\n",
stderr);
return 1;
}
memset(streams, 0, sizeof(streams));
streams[0].filename = argv[2];
streams[1].handler = handle_output;
streams[2].handler = handle_error;
handles[0] = CreateDetachedProcess(argv[1], streams);
handles[1] = streams[1].handle;
handles[2] = streams[2].handle;
WaitForMultipleObjects(3, handles, TRUE, INFINITE);
for ( i=0; i<3; i++)
CloseHandle(handles[i]);
return 0;
}
#endif
As I understand you are using windows (because you mentioned process informaiton). If you want to get the launched process output, you must capture its output stream. Here's an explanatory link which shoes how it can be done.
my2c