Skip to content

Commit

Permalink
Merge pull request #429 from pmj/ioshareddataqueue-workaround-dylib
Browse files Browse the repository at this point in the history
Mac PrjFSLib: Use IOSharedDataQueue workaround library if available
  • Loading branch information
pmj authored Oct 28, 2018
2 parents b471dd4 + c7e221b commit 920fe27
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 5 deletions.
6 changes: 3 additions & 3 deletions ProjFS.Mac/PrjFSLib/PrjFSLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ PrjFS_Result PrjFS_StartVirtualizationInstance(

while (1)
{
IODataQueueEntry* entry = IODataQueuePeek(dataQueue.queueMemory);
IODataQueueEntry* entry = DataQueue_Peek(dataQueue.queueMemory);
if (nullptr == entry)
{
// No more items in queue
Expand All @@ -226,13 +226,13 @@ PrjFS_Result PrjFS_StartVirtualizationInstance(
if (messageSize < sizeof(Message))
{
cerr << "Bad message size: got " << messageSize << " bytes, expected minimum of " << sizeof(Message) << ", skipping. Kernel/user version mismatch?\n";
IODataQueueDequeue(dataQueue.queueMemory, nullptr, nullptr);
DataQueue_Dequeue(dataQueue.queueMemory, nullptr, nullptr);
continue;
}

void* messageMemory = malloc(messageSize);
uint32_t dequeuedSize = messageSize;
IOReturn result = IODataQueueDequeue(dataQueue.queueMemory, messageMemory, &dequeuedSize);
IOReturn result = DataQueue_Dequeue(dataQueue.queueMemory, messageMemory, &dequeuedSize);
if (kIOReturnSuccess != result || dequeuedSize != messageSize)
{
cerr << "Unexpected result dequeueing message - result 0x" << hex << result << " dequeued " << dequeuedSize << "/" << messageSize << " bytes\n";
Expand Down
109 changes: 109 additions & 0 deletions ProjFS.Mac/PrjFSLib/PrjFSUser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
#include <IOKit/IOKitLib.h>
#include <iostream>
#include <mach/mach_port.h>
#include <sys/utsname.h>
#include <dlfcn.h>

struct DarwinVersion
{
unsigned long major, minor, revision;
};

typedef decltype(IODataQueueDequeue)* ioDataQueueDequeueFunctionPtr;
static ioDataQueueDequeueFunctionPtr ioDataQueueDequeueFunction = nullptr;
typedef decltype(IODataQueuePeek)* ioDataQueuePeekFunctionPtr;
static ioDataQueuePeekFunctionPtr ioDataQueuePeekFunction = nullptr;

static void InitDataQueueFunctions();


io_connect_t PrjFSService_ConnectToDriver(enum PrjFSServiceUserClientType clientType)
Expand Down Expand Up @@ -122,3 +136,98 @@ bool PrjFSService_DataQueueInit(
return false;
}

IOReturn DataQueue_Dequeue(IODataQueueMemory* dataQueue, void* data, uint32_t* dataSize)
{
if (nullptr == ioDataQueueDequeueFunction)
{
InitDataQueueFunctions();
}
return ioDataQueueDequeueFunction(dataQueue, data, dataSize);
}

IODataQueueEntry* DataQueue_Peek(IODataQueueMemory* dataQueue)
{
if (nullptr == ioDataQueuePeekFunction)
{
InitDataQueueFunctions();
}
return ioDataQueuePeekFunction(dataQueue);
}


static bool GetDarwinVersion(DarwinVersion& outVersion)
{
utsname unameInfo = {};
if (0 != uname(&unameInfo))
{
return false;
}

char* fieldEnd = nullptr;
unsigned long majorVersion = strtoul(unameInfo.release, &fieldEnd, 10);
if (nullptr == fieldEnd || *fieldEnd != '.')
{
return false;
}

unsigned long minorVersion = strtoul(fieldEnd + 1, &fieldEnd, 10);
if (nullptr == fieldEnd || (*fieldEnd != '.' && *fieldEnd != '\0'))
{
return false;
}

outVersion.major = majorVersion;
outVersion.minor = minorVersion;
outVersion.revision = 0;

if (*fieldEnd != '\0')
{
unsigned long revision = strtoul(fieldEnd + 1, &fieldEnd, 10);
if (nullptr == fieldEnd || (*fieldEnd != '.' && *fieldEnd != '\0'))
{
return false;
}
outVersion.revision = revision;
}

return true;
}

static void InitDataQueueFunctions()
{
ioDataQueueDequeueFunction = &IODataQueueDequeue;
ioDataQueuePeekFunction = &IODataQueuePeek;

DarwinVersion osVersion = {};
if (!GetDarwinVersion(osVersion))
{
return;
}

if ((osVersion.major == 17 && osVersion.minor >= 7) // macOS 10.13.6+
|| (osVersion.major == 18 && osVersion.minor == 0)) // macOS 10.14(.0) exactly
{
void* dataQueueLibrary = dlopen("libSharedDataQueue.dylib", RTLD_LAZY);
if (nullptr == dataQueueLibrary)
{
fprintf(stderr, "Error opening data queue client library: %s\n", dlerror());
}
else
{
void* sym = dlsym(dataQueueLibrary, "IODataQueueDequeue");
if (nullptr != sym)
{
ioDataQueueDequeueFunction = reinterpret_cast<ioDataQueueDequeueFunctionPtr>(sym);
}

sym = dlsym(dataQueueLibrary, "IODataQueuePeek");
if (nullptr != sym)
{
ioDataQueuePeekFunction = reinterpret_cast<ioDataQueuePeekFunctionPtr>(sym);
}

// Allow the dataQueueLibrary handle to leak; if we called dlclose(),
// the library would be unloaded, breaking our function pointers.
}
}
}
3 changes: 3 additions & 0 deletions ProjFS.Mac/PrjFSLib/PrjFSUser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ bool PrjFSService_DataQueueInit(
uint32_t clientPortType,
uint32_t clientMemoryType,
dispatch_queue_t eventHandlingQueue);

IODataQueueEntry* DataQueue_Peek(IODataQueueMemory* dataQueue);
IOReturn DataQueue_Dequeue(IODataQueueMemory* dataQueue, void* data, uint32_t* dataSize);
4 changes: 2 additions & 2 deletions ProjFS.Mac/PrjFSLib/prjfs-log/prjfs-log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ int main(int argc, const char * argv[])

while(true)
{
IODataQueueEntry* entry = IODataQueuePeek(dataQueue.queueMemory);
IODataQueueEntry* entry = DataQueue_Peek(dataQueue.queueMemory);
if(entry == nullptr)
{
break;
Expand All @@ -65,7 +65,7 @@ int main(int argc, const char * argv[])
lineCount++;
}

IODataQueueDequeue(dataQueue.queueMemory, nullptr, nullptr);
DataQueue_Dequeue(dataQueue.queueMemory, nullptr, nullptr);
}
});
dispatch_resume(dataQueue.dispatchSource);
Expand Down

0 comments on commit 920fe27

Please sign in to comment.