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.
Related
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 have a file which will be read and write by the multiple process. So to synchronize the file between multiple processes I was using fcntl().
Let's assume we have a file orignal.txt and we have some content in the orignal.txt. Assume the contents in the file are:
show core status
show table status
show action status
Now let's say we have three process A,B,C which would be accessing orignal.txt for deleting the content from it. Say A will delete show core status. B will delete show table status and C will delete show action status.
Actually show core status,show table status and show action status are some commands which is related to particular process, So I am assuming show core status is related to A so whenever A will come he will write show core status into the file orignal.txtand before A terminates it will delete the show core status from the file orignal.txt. Same with other processes also.
So for that I have written the code.
Note: This is a common API for deleting the content from the file which all three processes (A,B,C) will use.
#define ACQUIRE_LOCK 1
#define RELEASE_LOCK 0
int delete_content_from_file(char *command)
{
FILE *fp, *tempFd;
char buf[4096];
int ret;
fp = fopen ("orignal.txt", "r+");
if (fp == NULL)
{
printf("orignal.txt does not exist");
return -1;
}
printf("Acquiring lock for orignal.txt");
ret = fileSync(fp,ACQUIRE_LOCK,F_WRLCK);
if(ret == -1)
{
printf("Failed to acquire lock");
exit(EXIT_FAILURE);
}
tempFd = fopen ("duplicate.txt", "w");
if (tempFd == NULL)
{
printf("Duplicate.txt not exist");
return -1;
}
// read text until newline
while (!feof(fp))
{
if (fgets (buf, sizeof(buf), fp) != NULL)
{
buf[strlen(buf)-1]='\0';
if ((ret = strcmp (command, buf)) != 0) {
fprintf(tempFd, "%s\n", buf);
}
}
fclose(tempFd);
system("cp duplicate.txt orignal.txt");
remove("duplicate.txt");
printf("Releasing lock");
ret = fileSync(fp,RELEASE_LOCK,F_UNLCK);
if(ret == -1)
{
printf("unable to release the lock for orignal.txt");
return -1;
}
fclose (fp);
return 0;
}
int fileSync(FILE *fd,bool flag,short lock_type)
{
struct flock lock;
lock.l_type = lock_type;
lock.l_whence = SEEK_SET; // Starting from the begining of the file
lock.l_start = 0; // no offset
lock.l_len = 0; // to the end of file. 0 means EOF
if(flag == ACQUIRE_LOCK)
{
if(fcntl(fileno(fd), F_SETLKW, &lock) < 0)
{
perror("Error to acquire lock");
return -1;
}
}
else
{
if(fcntl(fileno(fd), F_UNLCK, &lock) < 0)
{
perror("Error releasing lock");
return -1;
}
}
return 0;
}
What I expected : When A will release the lock, the content of the file should become
show table status
show action status
and when B will release the lock, the content of the file should become
show action status
and when C will release the lock, the file will become empty.
But
What I got: When A has released the lock, content of the file is same. All three lines are present. But When B has released the lock , I saw B has deleted the content show table status from the file and same C also deleted the show action status
This is not fixed behaviour, sometimes B does not delete the content but A deletes or C deletes.
I have got struck at this point. Looks to me that file is not getting sync between processes. Any help will be appreciated. Thanks in Advance!
I am using the following code to check if a file is being used by another application:
HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "The file is in use", "Error", 0);
}
If the file is being used by another application, the message box is displayed. However, the message box is also displayed if the file does not exists!
So what should I do to solve this problem, should I also check if the file exists (using another function), or can the parameters of CreateFile() be changed to only return INVALID_HANDLE_VALUE if the file is in use and does exists?
If you wish to find out, which process has a file open, use the Restart Manager. The procedure consists of the following steps (as outlined in Raymond Chen's blog entry How do I find out which process has a file open?):
Create a Restart Manager session (RmStartSession).
Add a file resource to the session (RmRegisterResource).
Ask for a list of all processes affected by that resource (RmGetList).
Close the session (RmEndSession).
Sample code:
#include <Windows.h>
#include <RestartManager.h>
#pragma comment(lib, "Rstrtmgr.lib")
bool IsFileLocked( const wchar_t* PathName ) {
bool isFileLocked = false;
DWORD dwSession = 0x0;
wchar_t szSessionKey[CCH_RM_SESSION_KEY + 1] = { 0 };
if ( RmStartSession( &dwSession, 0x0, szSessionKey ) == ERROR_SUCCESS ) {
if ( RmRegisterResources( dwSession, 1, &PathName,
0, NULL, 0, NULL ) == ERROR_SUCCESS ) {
DWORD dwReason = 0x0;
UINT nProcInfoNeeded = 0;
UINT nProcInfo = 0;
if ( RmGetList( dwSession, &nProcInfoNeeded,
&nProcInfo, NULL, &dwReason ) == ERROR_MORE_DATA ) {
isFileLocked = ( nProcInfoNeeded != 0 );
}
}
RmEndSession( dwSession );
}
return isFileLocked;
}
You need to use GetLastError() to know why CreateFile() failed, eg:
// this is requesting exclusive access to the file, so it will
// fail if the file is already open for any reason. That condition
// is detected by a sharing violation error due to conflicting
// sharing rights...
HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
switch (GetLastError())
{
case ERROR_PATH_NOT_FOUND:
case ERROR_FILE_NOT_FOUND:
MessageBox(NULL, "The file does not exist", "Error", 0);
break;
case ERROR_SHARING_VIOLATION:
MessageBox(NULL, "The file is in use", "Error", 0);
break;
//...
default:
MessageBox(NULL, "Error opening the file", "Error", 0);
break;
}
}
else
{
// the file exists and was not in use.
// don't forget to close the handle...
CloseHandle(fh);
}
I'm trying to write an IRC type chat client which has clients that can connected to a server. I'm trying to get it to work locally atm (Using FIFOS instead of sockets).
I've run into the following issue which I can't seem to solve:
After accepting a new client connection, I want to create a new thread for that client (on the server) that'll handle inputs from that client.
To do this I have the following piece of code (the full code is at the bottom):
while(1) {
.
.
.
if (pthread_create(&thread, NULL, client_handler, &new_client) != 0)
printf("Couldn't create a thread to listen to the client.... Not ok \n");
}
This works fine with 1 connected client.
The moment I try to connect another client it seems the previous thread that executed the method client_handler stopped running.
I know this because the server stops accepting input from that client, but the new thread works just fine (the one that handles the newly connected client).
I was wondering if my methodology was wrong or if I'm not using the pthread_create correctly.
Has anyone got any suggestions?
void server_listen() {
Client new_client;
ClientNode temp;
buffint client_name_length;
char client_name[CLIENT_NAME_SIZE];
char fifo_in[FIFO_NAME_SIZE], fifo_out[FIFO_NAME_SIZE];
buffint client_pid;
char ack[4] = "/ack";
char inuse[6] = "/inuse";
pthread_t thread;
buffint length;
ClientNode it;
buffint message_length;
char message[MESSAGE_LENGTH];
pthread_mutexattr_t attr;
while (1) {
memset(client_name, 0, CLIENT_NAME_SIZE);
client_name_length.data =0;
if (read_helper(irc_server.server_fifo, client_name_length.buff,
sizeof(int)) == -1)
return; /* error */
if (read_helper(irc_server.server_fifo, client_pid.buff, sizeof(int))
== -1)
return; /* error */
if (read_helper(irc_server.server_fifo, client_name, client_name_length.data) == -1)
return; /* error */
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init(&new_client.fifo_in_lock, &attr);
printf("Reading from a new client, with name: %s\n", client_name);
new_client.pid = client_pid.data;
strncpy(new_client.name, client_name, client_name_length.data);
new_client.name_length = client_name_length.data;
sprintf(fifo_in, "fifo-%d-in", client_pid.data);
sprintf(fifo_out, "fifo-%d-out", client_pid.data);
new_client.fifo_in = open(fifo_in, O_WRONLY);
if (new_client.fifo_in == -1)
return; /* error */
new_client.fifo_out = open(fifo_out, O_RDONLY);
if (new_client.fifo_out == -1)
return; /* error */
read_lock();
temp = client_exists_by_name(&irc_server.clients, client_name, client_name_length.data);
read_unlock();
if (temp != NULL) {
pthread_mutex_lock(&new_client.fifo_in_lock);
length.data = 6;
if (write_helper(new_client.fifo_in, length.buff, sizeof(int))
== -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf( "Writing to the fifo-out failed for some unknown reason \n");
return;
}
if (write_helper(new_client.fifo_in, inuse, length.data) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf( "Writing to the fifo-out failed for some unknown reason \n");
return;
}
pthread_mutex_unlock(&new_client.fifo_in_lock);
continue;
}
write_lock();
insert_node(&irc_server.clients, new_client);
write_unlock();
length.data = 4;
pthread_mutex_lock(&new_client.fifo_in_lock);
if (write_helper(new_client.fifo_in, length.buff, sizeof(int)) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf("Writing to the fifo-out failed for some unknown reason \n");
return;
}
if (write_helper(new_client.fifo_in, ack, length.data) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf("Writing to the fifo-out failed for some unknown reason \n");
return;
}
pthread_mutex_unlock(&new_client.fifo_in_lock);
foreach(it, irc_server.clients){
pthread_mutex_lock(&it->client.fifo_in_lock);
strncpy(message, new_client.name, new_client.name_length);
strncat(message, " joined the chat", sizeof(" joined the chat"));
message_length.data = sizeof(" joined the chat") + new_client.name_length;
if (write_helper(it->client.fifo_in, message_length.buff, sizeof(int)) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf("writing to the fifo_in a public message ERROR1 \n");
return;
}
if (write_helper(it->client.fifo_in, message, message_length.data) == -1) {
//TODO: What do we do if writing to the fifo_out failed?
printf("writing to the fifo_in a public message ERROR2 \n");
return;
}
pthread_mutex_unlock(&it->client.fifo_in_lock);
memset(message, 0, MESSAGE_LENGTH);
message_length.data = 0;
}
if (pthread_create(&thread, NULL, client_handler, &new_client) != 0)
printf("Couldn't create a thread to listen to the client.... Not ok \n");
if (pthread_create(&thread, NULL,client_handler1 ,&new_client ) != 0)
printf("Couldn't create a thread to listen to the client.... Not ok \n");
print_clients();
}
}
It looks like you're sharing a single instance of new_client between all the threads in the server. A call to pthread_create() doesn't magically copy new_client. So every thread you create is using the same new_client. So when your master thread fills in values for a second client, the thread handling the first client tries to use those too.
Allocate a new new_client for each client, fill in the values and pass that into pthread_create(). You'll also need a per-client variable for the first parameter in pthread_create().
Other things - you're seemingly passing raw binary data between your client and server, things like string length integers. That kind of thing is going to cause you a whole pile of woe as soon as you have to start doing clients for different OSes. I strongly recommend you adopt a serialisation technology, preferably ASN.1 (not free but really robust) or Google Protocol Buffers (free but not as rich or robust).
if (pthread_create(&thread, NULL,client_handler ,&new_client ) != 0)
...
if (pthread_create(&thread, NULL,client_handler1 ,&new_client ) != 0)
Why you are using same pthread_t variable every time? You can't use same thread variable. Prefer to use an array of pthread_t like this:
pthread_t thread[2];
if (pthread_create(&thread[0], NULL, client_handler, &new_client ) != 0)
...
if (pthread_create(&thread[1], NULL, client_handler1, &new_client ) != 0)
I'm trying to read memory from a process (calc.exe). But I'm hitting "Could not read memory" message. Where is my mistake?
int main() {
HWND handle = FindWindow(0, TEXT("Calculadora"));
if (!handle) {
msg("Could not find window");
return 0;
}
DWORD id;
GetWindowThreadProcessId(handle, &id);
HANDLE proc = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, id);
if (!proc) {
msg("Could not open process");
return 0;
}
char buffer[128];
if (ReadProcessMemory(proc, 0, &buffer, 128, NULL)) {
msg("yes!!");
}
else {
msg("Could not read memory");
}
CloseHandle(proc);
}
You are attempting to read address 0 in the target process. That will always fail. You need to read from an address which is meaningful in the virtual address space of the target process.
Note that in order to call ReadProcessMemory you only need PROCESS_VM_READ. That's not the problem here, but I thought I would point it out for sake of completeness.