Help needed with F_NOCACHE in mac - macos

I am Srinivasa Raghavan and new to this group.
I am facing problem with non caching the file.
the code looks like the below:
main()
{
int fd;
char buf[512] = {'\0'};
fd = fopen("Sample.bin",O_RDONLY);
fcntl(fd, F_NOCACHE, 1);
fcntl(fd, F_RDAHEAD, 1);
read(fd, buf, sizeof(buf));
close(fd);
if(buf[0] == 'x' )
print("non-cached\n");
else
printf("cached\n")
}
the problem was, the F_NOCACHE doesn't not work properly, and all the time I get the message cached only. The firware will always update the value 'x' in sample.bin.
the above code works if I put the entire stuff (open, fcntl, read and close) in an indefinite loop (take long time to come out) like the below.
main()
{
while(1)
{
open...
fcntl(.., F_NOCACHE)
read(....
close..
if(buf[0] == 'x')
break;
}
}
I am really stuck with this for a week time, I want to know the exact behaviour of F_NOCACHE, and any information will be highly appreciated.
Thanks in advance,
Srinivasa Raghavan

That's not what it's for. F_NOCACHE tells the system that you don't expect to read that data* off the disk again any time soon, so it shouldn't bother caching it.
*Yes, "data" is plural, I know.

Related

Is there a way to read the NET_BUFFER at once?

I made NDIS 6 network filter driver and am reading the packet.
When I use Intel I350 NIC, 'MmGetMdlByteCount' returns '9014'bytes.
This value is the same as the MTU size, so I can read the data at once.
However, when using the x540 NIC, 'MmGetMdlByteCount' is returned to '2048'bytes.
So I have to read the MDL over and over again. Why is this happening?
Is there a way to read data at once on the X540 NIC?
I want to reduce repetition because I think the consumption time will be longer if I bring the data several times.
Below is a part of my source code.
PVOID vpByTmpData = NULL;
for( pNbMdl = NET_BUFFER_CURRENT_MDL( pNetBuffer );
pNbMdl != NULL && ulDataLength > 0;
pNbMdl = NDIS_MDL_LINKAGE( pNbMdl ) )
{
ulBytesToCopy = MmGetMdlByteCount( pNbMdl );
if( ulBytesToCopy == 0 )
continue;
vpByTmpData = MmGetSystemAddressForMdlSafe( pNbMdl, NormalPagePriority );
if( !vpByTmpData )
{
bRet = FALSE;
__leave;
}
if( ulBytesToCopy > ulDataLength )
ulBytesToCopy = ulDataLength;
NdisMoveMemory( &baImage[ulMemIdxOffset], (PBYTE)(vpByTmpData), ulBytesToCopy);
ulMemIdxOffset += ulBytesToCopy;
}
Please help me.
What you're seeing is a result of how the NIC hardware physically works. Different hardware will use different buffer layout strategies. NDIS does not attempt to force every NIC to use the same strategy, since that would reduce performance on some NICs. Unfortunately for you, that means the complexity of dealing with different buffers gets pushed upwards into NDIS filter & protocol drivers.
You can use NdisGetDataBuffer to do some of this work for you. Internally, NdisGetDataBuffer works like this:
if MmGetSystemAddressForMdl fails:
return NULL;
else if the payload is already contiguous in memory:
return a pointer to that directly;
else if you provided your own buffer:
copy the payload into your buffer
return a pointer to your buffer;
else:
return NULL;
So you can use NdisGetDataBuffer to obtain a contiguous view of the payload. The simplest way to use it is this:
UCHAR ScratchBuffer[MAX_MTU_SIZE];
UCHAR *Payload = NdisGetDataBuffer(NetBuffer, NetBuffer->DataLength, ScratchBuffer, 1, 0);
if (!Payload) {
return NDIS_STATUS_RESOURCES; // very unlikely: MmGetSystemAddressForMdl failed
}
memcpy(baImage, Payload, NetBuffer->DataLength);
But this can have a double-copy in some cases. (Exercise to test your understanding: when would there be a double-copy?) For slightly better performance, you can avoid the double-copy with this trick:
UCHAR *Payload = NdisGetDataBuffer(NetBuffer, NetBuffer->DataLength, baImage, 1, 0);
if (!Payload) {
return NDIS_STATUS_RESOURCES; // very unlikely: MmGetSystemAddressForMdl failed
}
// Did NdisGetDataBuffer already copy the payload into my flat buffer?
if (Payload != baImage) {
// If not, copy from the MDL to my flat buffer now.
memcpy(baImage, Payload, NetBuffer->DataLength);
}
You haven't included a complete code sample, but I suspect there may be some bugs in your code. I don't see any attempt to handle NetBuffer->CurrentMdlOffset. While this is usually zero, it's not always zero, so your code would not always be correct.
Similarly, it looks like the copy isn't correctly constrained by ulDataLength. You would need a ulDataLength -= ulBytesToCopy in there somewhere to fix this.
I'm very sympathetic to how tricky it is to navigate NBLs, NBs, and MDLs -- my first NIC driver included a nasty bug in calculating MDL offsets. I have some MDL-handling code internally -- I will try to clean it up a bit and publish it at https://github.com/microsoft/ndis-driver-library/ in the next few days. I'll update this post if I get it published. I think there's clearly a need for some nice, reusable and well-documented sample code to just copy (subsets of) an MDL chain into a flat buffer, or vice-versa.
Update: Refer to MdlCopyMdlChainAtOffsetToFlatBuffer in mdl.h

No relevant answers on the actual behavior of kbhit() on characters such as ", %, ~ in Windows 10 when keyboard and locale are US (not international)

Windows 10 with latest updates installed on a Dell XPS13. US keyboard layout and US locale selected (not international). Still a call to kbhit() or _kbhit() with specific characters such as ", ~, % does not return the key hit, at least mot until a certain amount of time (~1second) and a second character has been hit.
I try to use kbhit() because I need a non-waiting function. How can I detect correctly a keyboard hit on " or % with a single keystroke?
In Linux using a timed-out select() on stdin works great, but doesn't seem to be OK with Windows.
Thanks,
-Patrick
I finally found a solution that fits my needs and fixes the issues I have with kbhit(); code below; I hope it helps others too.
– Patrick
int getkey();
//
// int getkey(): returns the typed character at keyboard or NO_CHAR if no keyboard key was pressed.
// This is done in non-blocking mode; i.e. NO_CHAR is returned if no keyboard event is read from the
// console event queue.
// This works a lot better for me than the standard call to kbhit() which is generally used as kbhit()
// keeps some characters such as ", `, %, and tries to deal with them before returning them. Not easy
// the to follow-up what's really been typed in.
//
int getkey() {
INPUT_RECORD buf; // interested in bKeyDown event
DWORD len; // seem necessary
int ch;
ch = NO_CHAR; // default return value;
PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &buf, 1, &len);
if (len > 0) {
if (buf.EventType == KEY_EVENT && buf.Event.KeyEvent.bKeyDown) {
ch = _getche(); // set ch to input char only under right conditions
} // _getche() returns char and echoes it to console out
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); // remove consumed events
} else {
Sleep(5); // avoids too High a CPU usage when no input
}
return ch;
}
It is also possible to call ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &buf, 1, &len); rather than FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); in the code above, but for some unknown reason, it doesn't seem to reply/react as quickly and some character are missed when typing at the keyboard.

Issues with CAPlayThrough Example

I am trying to learn Xcode Core Audio and stumbled upon this example:
https://developer.apple.com/library/mac/samplecode/CAPlayThrough/Introduction/Intro.html#//apple_ref/doc/uid/DTS10004443
My intention is to capture the raw audio. Everytime I hit a break point, I lose the audio. Since it is using CARingBuffer.
How would you remove the time factor.I don't need real-time audio.
Since it is using CARingBuffer it should keep on writing to same memory location? So why don't I hear the audio? If I have a breakpoint?
I am reading the Learning Core Audio book. But, so far I cannot figure out this part of the following code:
CARingBufferError CARingBuffer::Store(const AudioBufferList *abl, UInt32 framesToWrite, SampleTime startWrite)
{
if (framesToWrite == 0)
return kCARingBufferError_OK;
if (framesToWrite > mCapacityFrames)
return kCARingBufferError_TooMuch; // too big!
SampleTime endWrite = startWrite + framesToWrite;
if (startWrite < EndTime()) {
// going backwards, throw everything out
SetTimeBounds(startWrite, startWrite);
} else if (endWrite - StartTime() <= mCapacityFrames) {
// the buffer has not yet wrapped and will not need to
} else {
// advance the start time past the region we are about to overwrite
SampleTime newStart = endWrite - mCapacityFrames; // one buffer of time behind where we're writing
SampleTime newEnd = std::max(newStart, EndTime());
SetTimeBounds(newStart, newEnd);
}
// write the new frames
Byte **buffers = mBuffers;
int nchannels = mNumberChannels;
int offset0, offset1, nbytes;
SampleTime curEnd = EndTime();
if (startWrite > curEnd) {
// we are skipping some samples, so zero the range we are skipping
offset0 = FrameOffset(curEnd);
offset1 = FrameOffset(startWrite);
if (offset0 < offset1)
ZeroRange(buffers, nchannels, offset0, offset1 - offset0);
else {
ZeroRange(buffers, nchannels, offset0, mCapacityBytes - offset0);
ZeroRange(buffers, nchannels, 0, offset1);
}
offset0 = offset1;
} else {
offset0 = FrameOffset(startWrite);
}
offset1 = FrameOffset(endWrite);
if (offset0 < offset1)
StoreABL(buffers, offset0, abl, 0, offset1 - offset0);
else {
nbytes = mCapacityBytes - offset0;
StoreABL(buffers, offset0, abl, 0, nbytes);
StoreABL(buffers, 0, abl, nbytes, offset1);
}
// now update the end time
SetTimeBounds(StartTime(), endWrite);
return kCARingBufferError_OK; // success
}
Thanks!
If I understood the question well, the signal is lost while input unit (producer) being halted on a breakpoint. I presume this may be the expected behavior. CoreAudio is a pull-model engine running of the real time thread. This means under some conditions your producer hits a breakpoint, the ring buffer empties, the output unit (consumer) keeps on running, but gets nothing from the buffer while the playthrough chain is interrupted, hence the possible silence.
Perhaps this code from the example is not really the simplest one: I see it also zeroes audio buffers if ring buffer gets overrun/underrun, AFAICT.
The term "raw audio" in the question is also not self-explanatory, I'm not sure what does it mean. I would suggest trying to learn async i/o using simpler circular buffers. There are few of them (without obligatory time values) on GitHub.
Please also be so kind to format the source code for easier reading.

How Should I read a File line-by-line in C?

I'd like to read a file line-by-line. I have fgets() working okay, but am not sure what to do if a line is longer than the buffer sizes I've passed to fgets()? And furthermore, since fgets() doesn't seem to be Unicode-aware, and I want to allow UTF-8 files, it might miss line endings and read the whole file, no?
Then I thought I'd use getline(). However, I'm on Mac OS X, and while getline() is specified in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/usr/include/stdio.h, it's not in /usr/include/stdio, so gcc doesn't find it in the shell. And it's not particularly portable, obviously, and I'd like the library I'm developing to be generally useful.
So what's the best way to read a file line-by-line in C?
First of all, it's very unlikely that you need to worry about non-standard line terminators like U+2028. Normal text files are not expected to contain them, and the very overwhelming majority of all existing software that reads normal text files doesn't support them. You mention getline() which is available in glibc but not in MacOS's libc, and it would surprise me if getline() did support such fancy line terminators. It's almost a certainly that you can get away with just supporting LF (U+000A) and maybe also CR+LF (U+000D U+000A). To do that, you don't need to care about UTF-8. That's the beauty of UTF-8's ASCII compatibility and is by design.
As for supporting lines that are longer than the buffer you pass to fgets(), you can do this with a little extra logic around fgets. In pseudocode:
while true {
fgets(buffer, size, stream);
dynamically_allocated_string = strdup(buffer);
while the last char (before the terminating NUL) in the buffer is not '\n' {
concatenate the contents of buffer to the dynamically allocated string
/* the current line is not finished. read more of it */
fgets(buffer, size, stream);
}
process the whole line, as found in the dynamically allocated string
}
But again, I think you will find that there's really quite a lot of software out there that simply doesn't bother with that, from software that parses system config files like /etc/passwd to (some) scripting languages. Depending on your use case, it may very well be good enough to use a "big enough" buffer (e.g. 4096 bytes) and declare that you don't support lines longer than that. You can even call it a security feature (a line length limit is protection against resource exhaustion attacks from a crafted input file).
Based on this answer, here's what I've come up with:
#define LINE_BUF_SIZE 1024
char * getline_from(FILE *fp) {
char * line = malloc(LINE_BUF_SIZE), * linep = line;
size_t lenmax = LINE_BUF_SIZE, len = lenmax;
int c;
if(line == NULL)
return NULL;
for(;;) {
c = fgetc(fp);
if(c == EOF)
break;
if(--len == 0) {
len = lenmax;
char * linen = realloc(linep, lenmax *= 2);
if(linen == NULL) {
// Fail.
free(linep);
return NULL;
}
line = linen + (line - linep);
linep = linen;
}
if((*line++ = c) == '\n')
break;
}
*line = '\0';
return linep;
}
To read stdin:
char *line;
while ( line = getline_from(stdin) ) {
// do stuff
free(line);
}
To read some other file, I first open it with fopen():
FILE *fp;
fp = fopen ( filename, "rb" );
if (!fp) {
fprintf(stderr, "Cannot open %s: ", argv[1]);
perror(NULL);
exit(1);
}
char *line;
while ( line = getline_from(fp) ) {
// do stuff
free(line);
}
This works very nicely for me. I'd love to see an alternative that uses fgets() as suggested by #paul-tomblin, but I don't have the energy to figure it out tonight.

Events/Interrupts in Serial Communication

I want to read and write from serial using events/interrupts.
Currently, I have it in a while loop and it continuously reads and writes through the serial. I want it to only read when something comes from the serial port. How do I implement this in C++?
This is my current code:
while(true)
{
//read
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
}
//write
if(!WriteFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
}
//print what you are reading
printf("%s\n", szBuff);
}
Use a select statement, which will check the read and write buffers without blocking and return their status, so you only need to read when you know the port has data, or write when you know there's room in the output buffer.
The third example at http://www.developerweb.net/forum/showthread.php?t=2933 and the associated comments may be helpful.
Edit: The man page for select has a simpler and more complete example near the end. You can find it at http://linux.die.net/man/2/select if man 2 select doesn't work on your system.
Note: Mastering select() will allow you to work with both serial ports and sockets; it's at the heart of many network clients and servers.
For a Windows environment the more native approach would be to use asynchronous I/O. In this mode you still use calls to ReadFile and WriteFile, but instead of blocking you pass in a callback function that will be invoked when the operation completes.
It is fairly tricky to get all the details right though.
Here is a copy of an article that was published in the c/C++ users journal a few years ago. It goes into detail on the Win32 API.
here a code that read serial incomming data using interruption on windows
you can see the time elapsed during the waiting interruption time
int pollComport(int comport_number, LPBYTE buffer, int size)
{
BYTE Byte;
DWORD dwBytesTransferred;
DWORD dwCommModemStatus;
int n;
double TimeA,TimeB;
// Specify a set of events to be monitored for the port.
SetCommMask (m_comPortHandle[comport_number], EV_RXCHAR );
while (m_comPortHandle[comport_number] != INVALID_HANDLE_VALUE)
{
// Wait for an event to occur for the port.
TimeA = clock();
WaitCommEvent (m_comPortHandle[comport_number], &dwCommModemStatus, 0);
TimeB = clock();
if(TimeB-TimeA>0)
cout <<" ok "<<TimeB-TimeA<<endl;
// Re-specify the set of events to be monitored for the port.
SetCommMask (m_comPortHandle[comport_number], EV_RXCHAR);
if (dwCommModemStatus & EV_RXCHAR)
{
// Loop for waiting for the data.
do
{
ReadFile(m_comPortHandle[comport_number], buffer, size, (LPDWORD)((void *)&n), NULL);
// Display the data read.
if (n>0)
cout << buffer <<endl;
} while (n > 0);
}
return(0);
}
}

Resources