From: <ped...@us...> - 2007-06-10 07:47:23
|
Revision: 934 http://svn.sourceforge.net/cegcc/?rev=934&view=rev Author: pedroalves Date: 2007-06-09 10:47:55 -0700 (Sat, 09 Jun 2007) Log Message: ----------- Adding PipeLib's device, lib and testers. Added Paths: ----------- trunk/cegcc/tools/PipeLib/ trunk/cegcc/tools/PipeLib/PipeDev/ trunk/cegcc/tools/PipeLib/PipeDev/Makefile trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.cpp trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.h trunk/cegcc/tools/PipeLib/PipeLib/ trunk/cegcc/tools/PipeLib/PipeLib/Makefile trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.cpp trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.h trunk/cegcc/tools/PipeLib/PipeTest/ trunk/cegcc/tools/PipeLib/PipeTest/Makefile trunk/cegcc/tools/PipeLib/PipeTest/PipeTest.cpp trunk/cegcc/tools/PipeLib/TestClient/ trunk/cegcc/tools/PipeLib/TestClient/Makefile trunk/cegcc/tools/PipeLib/TestClient/TestClient.cpp Added: trunk/cegcc/tools/PipeLib/PipeDev/Makefile =================================================================== --- trunk/cegcc/tools/PipeLib/PipeDev/Makefile (rev 0) +++ trunk/cegcc/tools/PipeLib/PipeDev/Makefile 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,20 @@ +TARGET=arm-wince-mingw32ce + +CXX=$(TARGET)-g++ +AR=$(TARGET)-ar + +WARNFLAGS=-Wall -Wextra + +INCLUDES= + +ALLFLAGS=$(INCLUDES) $(CXXFLAGS) $(WARNFLAGS) + +all: PipeDev.dll + +PipeDev.dll: PipeDevice.cpp + $(CXX) $< -shared -o $@ $(ALLFLAGS) + +clean: + rm -f PipeDev.dll + +.PHONE: all clean Property changes on: trunk/cegcc/tools/PipeLib/PipeDev/Makefile ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.cpp =================================================================== --- trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.cpp (rev 0) +++ trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.cpp 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,911 @@ +/* Copyright (c) 2007, Pedro Alves + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include "PipeDevice.h" + +#include <windows.h> +#include <devload.h> +#include <set> +#include <string> + +#ifndef min +#define min(A, B) ((A) < (B) ? (A) : (B)) +#endif + +typedef struct _DEVICE_PSL_NOTIFY +{ + DWORD dwSize; + DWORD dwFlags; + HANDLE hProc; + HANDLE hThread; +} DEVICE_PSL_NOTIFY, *PDEVICE_PSL_NOTIFY; + +#ifndef FILE_DEVICE_PSL +#define FILE_DEVICE_PSL 259 +#endif + +#define IOCTL_PSL_NOTIFY \ + CTL_CODE (FILE_DEVICE_PSL, 255, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define DLL_PROCESS_EXITING 4 + +#define PIPEDEV_API extern "C" __declspec (dllexport) + +//#define DEBUG_MODE +//#define NOLOCKS +//#define DEBUG_LOCKS + +#ifdef DEBUG_LOCKS +# define G(CS) (__LINE__, CS) +#else +# define G(CS) (CS) +#endif + +class CSWrapper +{ +public: + explicit CSWrapper (CRITICAL_SECTION* cs) : cs_(*cs) {} + ~CSWrapper () {} + + void Lock () + { +#ifndef NOLOCKS + EnterCriticalSection (&cs_); +#endif + } + void Unlock () + { +#ifndef NOLOCKS + LeaveCriticalSection (&cs_); +#endif + } +private: + CRITICAL_SECTION& cs_; +}; + +class CS : public CSWrapper +{ +public: + CS () : CSWrapper (&cs_) + { +#ifndef NOLOCKS + InitializeCriticalSection (&cs_); +#endif + } + ~CS () + { +#ifndef NOLOCKS + DeleteCriticalSection (&cs_); +#endif + } +private: + CRITICAL_SECTION cs_; +}; + +class FastCS +{ +public: + FastCS () : Count(0) + { +#ifndef NOLOCKS + /* auto - only release one at a time. */ + EventHandle = CreateEvent (NULL, FALSE, FALSE, NULL); +#endif + } + ~FastCS () + { +#ifndef NOLOCKS + CloseHandle (EventHandle); +#endif + } + + void Lock () + { +#ifndef NOLOCKS + if (InterlockedIncrement (&Count) == 1) + /* first come - first serve. */ + return; + + /* everyone else, get in line. */ + WaitForSingleObject (EventHandle, INFINITE); +#endif + } + void Unlock () + { +#ifndef NOLOCKS + if (InterlockedDecrement (&Count) > 0) + /* release one pending */ + SetEvent (EventHandle); +#endif + } +private: + HANDLE EventHandle; + LONG Count; +}; + +class RecursiveCS +{ +public : + RecursiveCS () + : Count(0) + , RecursionCount(0) + , ThreadID(0) + + { +#ifndef NOLOCKS + /* auto - only release one at a time. */ + EventHandle = CreateEvent (NULL, FALSE, FALSE, NULL); +#endif + } + + ~RecursiveCS () + { +#ifndef NOLOCKS + CloseHandle (EventHandle); +#endif + } + + void Lock () + { +#ifndef NOLOCKS + if (ThreadID == GetCurrentThreadId ()) + { + InterlockedIncrement (&RecursionCount); + return; + } + + if (InterlockedIncrement (&Count) == 1) + InterlockedExchange (&RecursionCount, 0); + else + WaitForSingleObject (EventHandle, INFINITE); + + ThreadID = GetCurrentThreadId (); +#endif + } + + void Unlock () + { +#ifndef NOLOCKS + if (RecursionCount == 0) + { + if (InterlockedDecrement (&Count) > 0) + { + /* release one thread */ + SetEvent (EventHandle); + } + } + else + { + InterlockedDecrement (&RecursionCount); + } +#endif + } + +private: + HANDLE EventHandle; + LONG Count; + LONG RecursionCount; + DWORD ThreadID; +}; + + +template <class T> +class LockGuard +{ +public: +#ifdef DEBUG_LOCKS + LockGuard (int line, T &cs) : cs_(cs), lineno(line) + { + WCHAR buf[100]; + wsprintf (buf, L"line : %d", line); + MessageBoxW(0, buf, L"lock", 0); + + cs_.Lock (); + } + ~LockGuard () + { + WCHAR buf[100]; + wsprintf (buf, L"line : %d", lineno); + MessageBoxW(0, buf, L"unlock", 0); + + cs_.Unlock (); + } +#else + explicit LockGuard (T &cs) : cs_(cs) { cs_.Lock (); } + ~LockGuard () { cs_.Unlock (); } +#endif + +private: + T &cs_; + +#ifdef DEBUG_LOCKS + int lineno; +#endif +}; + +class PipeOpenContext; + +class PipeDeviceContext +{ +public: + typedef ::LockGuard<PipeDeviceContext> LockGuard; + + explicit PipeDeviceContext (LPCWSTR activepath) + : OpenCount(0) + , WROpenCount(0) + , DeviceName(NULL) + , Aborting(FALSE) + , head(0) + , count(0) + { + ActivePath = wcsdup (activepath); + ReadEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + WriteEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + + /* This should wake all threads, so it is manual reset. */ + AbortEvent = CreateEvent (NULL, TRUE, FALSE, NULL); + } + + ~PipeDeviceContext () + { + if (DeviceName) + free (DeviceName); + if (ActivePath) + free (ActivePath); + CloseHandle (ReadEvent); + CloseHandle (WriteEvent); + CloseHandle (AbortEvent); + } + + DWORD size () + { + return count; + } + + DWORD tail () + { + return (head + count) & (sizeof (buffer) - 1); + } + + void Lock () + { + cs.Lock (); + } + + void Unlock () + { + cs.Unlock (); + } + + DWORD writeBytes (const void* data_, DWORD dsize) + { + DWORD fit = sizeof (buffer) - size (); + fit = min (dsize, fit); + const BYTE* data = (const BYTE*)data_; + BYTE* b = buffer + tail (); + for (DWORD i = 0; i < fit; i++) + b[i & (sizeof (buffer) - 1)] = data[i]; + count += fit; + return fit; + } + + DWORD readBytes (void* buf_, DWORD bsize) + { + BYTE* buf = (BYTE*)buf_; + DWORD fit = min (bsize, size ()); + + const BYTE* h = buffer + head; + for (DWORD i = 0; i < fit; i++) + buf[i] = h[i & (sizeof (buffer) - 1)]; + count -= fit; + head += fit; + head &= (sizeof (buffer) - 1); + return fit; + } + +public: + DWORD OpenCount; + DWORD WROpenCount; + + WCHAR* ActivePath; + + HANDLE ReadEvent; + HANDLE WriteEvent; + HANDLE AbortEvent; + + WCHAR* DeviceName; + BOOL Aborting; + +private: + BYTE buffer[0x1000]; + DWORD head; + DWORD count; + + RecursiveCS cs; +}; + +class PipeOpenContext +{ +public: + PipeOpenContext (PipeDeviceContext* devctx, + DWORD accessCode, DWORD shareMode) + : DeviceContext (devctx) + , dwAccessCode (accessCode) + , dwShareMode (shareMode) + {} + + ~PipeOpenContext () + {} + + PipeDeviceContext* DeviceContext; + DWORD dwAccessCode; + DWORD dwShareMode; +}; + +static CRITICAL_SECTION open_pipes_cs; + +extern "C" BOOL WINAPI +DllMain (HANDLE /*hinstDLL*/, DWORD dwReason, LPVOID /*lpvReserved*/) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + InitializeCriticalSection (&open_pipes_cs); + break; + case DLL_PROCESS_DETACH: + DeleteCriticalSection (&open_pipes_cs); + break; + } + + return TRUE; +} + +static void +LogMessage (const char* msg, ...) +{ +#if 0 + va_list ap; + va_start (ap, msg); + FILE* log = fopen ("log.txt", "a+"); + vfprintf (log, msg, ap); + fclose (log); + va_end (ap); +#else + (void)msg; +#endif +} + +struct LogScope +{ + explicit LogScope (const char* func) + : func_(func) + { + LogMessage ("entering %s\n", func_); + } + ~LogScope () + { + LogMessage ("leaving %s\n", func_); + } + + const char* func_; +}; + +#define LOGSCOPE(MSG) LogScope scope ## __LINE__(#MSG) + +/* This is needed for MSVC. */ +struct ltwstr +{ + bool operator () (const std::wstring& s1, const std::wstring& s2) const + { + return wcscmp (s1.c_str (), s2.c_str ()) < 0; + } +}; + +typedef std::set<std::wstring, ltwstr> vwstring; +static vwstring open_pipes; + +PIPEDEV_API BOOL Deinit (PipeDeviceContext* pDeviceContext); + +static HANDLE +GetDeviceHandle (PipeDeviceContext* pDeviceContext) +{ + LOGSCOPE (GetDeviceHandle); + HKEY hActive; + DWORD Type; + HANDLE hDev = INVALID_HANDLE_VALUE; + + DWORD status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, pDeviceContext->ActivePath, + 0, 0, &hActive); + if (status != ERROR_SUCCESS) + return INVALID_HANDLE_VALUE; + + DWORD Len = sizeof(hDev); + status = RegQueryValueEx (hActive, DEVLOAD_HANDLE_VALNAME, NULL, &Type, + (PUCHAR)&hDev, &Len); + if (status != ERROR_SUCCESS) + { + /* weird */ + } + + RegCloseKey (hActive); + + return hDev; +} + +PIPEDEV_API DWORD +Init (LPCTSTR pContext) +{ + LOGSCOPE ("Init"); + CSWrapper cs (&open_pipes_cs); + LockGuard<CSWrapper> guard G(cs); + +#ifdef DEBUG_MODE + MessageBoxW (0, pContext, L"Init", 0); +#endif + + /* TODO: The key here isn't exactly the best. Maybe we should use + the device name instead, and get that from the registry - that would + also get rid of the IOCTL calls. */ + if (open_pipes.find (pContext) != open_pipes.end ()) + /* already open, PipeLib will try another one. */ + return 0; + + PipeDeviceContext* pDeviceContext = new PipeDeviceContext (pContext); + if (pDeviceContext == NULL) + return 0; + + open_pipes.insert (pContext); + + return (DWORD)pDeviceContext; +} + +#ifdef DEBUG_MODE +static int close_calls; +#endif + +PIPEDEV_API BOOL +Deinit (PipeDeviceContext* pDeviceContext) +{ + LOGSCOPE ("Deinit"); + /* All file handles must to be closed before deinitialising + the driver. */ + +#ifdef DEBUG_MODE + WCHAR buf[100]; + wsprintf (buf, L"opencount %d : calls %d", pDeviceContext->OpenCount, + close_calls); + MessageBoxW (0, buf, L"Deinit", 0); +#endif + + if (pDeviceContext == NULL) + return FALSE; + + { + PipeDeviceContext::LockGuard guard G(*pDeviceContext); + + if (pDeviceContext->OpenCount != 0) + return FALSE; + } + +#ifdef DEBUG_MODE + MessageBoxW (0, L"deactivate success", L"Deinit", 0); +#endif + + /* Allow reuse. */ + open_pipes.erase (pDeviceContext->ActivePath); + + /* Race? Is it possible that there can be another process + calling any function on the device while we are + Dinitializing it? Doesn't CE take care of that? */ + delete pDeviceContext; + return TRUE; +} + +PIPEDEV_API DWORD +Open (PipeDeviceContext* pDeviceContext, DWORD AccessCode, DWORD ShareMode) +{ + LOGSCOPE ("Open"); + +#ifdef DEBUG_MODE + wchar_t buf[100]; + wsprintf (buf, L"opencount %d", pDeviceContext->OpenCount); + MessageBoxW (0, buf, L"open 1", 0); +#endif + + PipeOpenContext* pOpenContext = + new PipeOpenContext (pDeviceContext, AccessCode, ShareMode); + +#ifdef DEBUG_MODE + MessageBoxW (0, L"going to lock", L"open 2", 0); +#endif + + PipeDeviceContext::LockGuard guard G(*pOpenContext->DeviceContext); + +#ifdef DEBUG_MODE + MessageBoxW (0, L"locked", L"open 3", 0); +#endif + + pDeviceContext->OpenCount++; + + if (AccessCode & GENERIC_WRITE) + pDeviceContext->WROpenCount++; + +#ifdef DEBUG_MODE + wsprintf (buf, L"opencount %d", pDeviceContext->OpenCount); + MessageBoxW (0, buf, L"open", 0); +#endif + + return (DWORD)pOpenContext; +} + +struct DeactivatorData +{ + HANDLE th; + HANDLE dev; +}; + +static DWORD WINAPI +Deactivator (void* arg) +{ + LOGSCOPE ("Deactivator"); + + DeactivatorData* data = (DeactivatorData*)arg; + +#ifdef DEBUG_MODE + wchar_t buf[100]; + wsprintf (buf, L"%x", data->dev); + MessageBoxW(0, buf, L"close: dev handle", 0); + if (!DeactivateDevice (data->dev)) + MessageBoxW(0, buf, L"deactivate failed", 0); + else + MessageBoxW(0, buf, L"after deactivate", 0); +#else + DeactivateDevice (data->dev); +#endif + + CloseHandle (data->th); + delete data; + + return 0; +} + +static void +DeactivatePipeDevice (PipeDeviceContext* dev) +{ + LOGSCOPE ("DeactivatePipeDevice"); + + HANDLE hdev = GetDeviceHandle (dev); + DeactivatorData* data = new DeactivatorData (); + data->dev = hdev; + data->th = CreateThread (NULL, 0, Deactivator, data, + CREATE_SUSPENDED, NULL); + ResumeThread (data->th); +} + +PIPEDEV_API BOOL +Close (PipeOpenContext* pOpenContext) +{ + LOGSCOPE ("Close"); +#ifdef DEBUG_MODE + close_calls++; + + wchar_t buf[100]; + if (pOpenContext) + { + wsprintf (buf, L"opencount %d : %p", + pOpenContext->DeviceContext->OpenCount, + pOpenContext); + MessageBoxW (0, buf, L"close", 0); + } + else + { + wsprintf (buf, L"openctx %p", pOpenContext); + MessageBoxW (0, buf, L"close", 0); + } +#endif + + if (pOpenContext == NULL) + return FALSE; + + PipeDeviceContext* dev = pOpenContext->DeviceContext; + + PipeDeviceContext::LockGuard guard G(*dev); + + if (dev->OpenCount == 0) + return FALSE; + + dev->OpenCount--; + + if (pOpenContext->dwAccessCode & GENERIC_WRITE) + { + dev->WROpenCount--; + if (dev->WROpenCount == 0) + /* Wake up the reading side so it can see + the broken pipe. */ + SetEvent (dev->AbortEvent); + } + + delete pOpenContext; + +#ifdef DEBUG_MODE + wsprintf (buf, L"opencount %d", dev->OpenCount); + MessageBoxW (0, buf, L"close 2", 0); +#endif + + if (dev->OpenCount == 0) + { +#if 0 + HANDLE hdev = GetDeviceHandle (dev); + DeactivateDevice (hdev); +#else + DeactivatePipeDevice (dev); +#endif + } + + return TRUE; +} + +PIPEDEV_API DWORD +Read (PipeOpenContext* pOpenContext, LPVOID pBuffer_, DWORD dwCount) +{ + LOGSCOPE ("Read"); + + if (IsBadReadPtr (pBuffer_, dwCount)) + { + SetLastError (ERROR_INVALID_PARAMETER); + return -1; + } + + BYTE* pBuffer = (BYTE*)pBuffer_; + DWORD needed = dwCount; + + if (pOpenContext == NULL + || (pOpenContext->dwAccessCode & GENERIC_READ) == 0) + return (DWORD)-1; + + PipeDeviceContext* dev = pOpenContext->DeviceContext; + + BOOL breaknext = FALSE; + HANDLE Events[2]; + + do + { + { + PipeDeviceContext::LockGuard guard G(*dev); + + Events[0] = dev->WriteEvent; + Events[1] = dev->AbortEvent; + + if (dev->Aborting) + /* this device is long gone */ + return (DWORD)-1; + + if (dev->WROpenCount == 0) + /* broken pipe */ + return (DWORD)-1; + + if (dev->OpenCount == 0) + /* weird */ + return (DWORD)-1; + + DWORD read = dev->readBytes (pBuffer, dwCount); + pBuffer += read; + dwCount -= read; + + if (read) + SetEvent (dev->ReadEvent); + + if (dwCount == 0) + break; + + if (breaknext) + break; + } + + switch (WaitForMultipleObjects (2, Events, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + breaknext = TRUE; + break; + default: + // MessageBoxW (0, L"pipe aborted", L"Read", 0); + /* With either wait error or AbortEvent + signaled, return with error. */ + return (DWORD)-1; + } + } + while (dwCount); + + return needed - dwCount; +} + +PIPEDEV_API DWORD +Write (PipeOpenContext* pOpenContext, LPCVOID pBuffer_, DWORD dwCount) +{ + LOGSCOPE ("Write"); + + if (IsBadReadPtr (pBuffer_, dwCount)) + { + SetLastError (ERROR_INVALID_PARAMETER); + return -1; + } + + const BYTE* pBuffer = (const BYTE*)pBuffer_; + DWORD needed = dwCount; + +#ifdef DEBUG_MODE + wchar_t buf[100]; + wsprintf (buf, L"opencount %d", pOpenContext->DeviceContext->OpenCount); + MessageBoxW (0, buf, L"write", 0); +#endif + + if (pOpenContext == NULL + || (pOpenContext->dwAccessCode & GENERIC_WRITE) == 0) + return (DWORD)-1; + + PipeDeviceContext* dev = pOpenContext->DeviceContext; + + BOOL breaknext = FALSE; + HANDLE Events[2]; + + do + { + { + PipeDeviceContext::LockGuard guard G(*dev); + +#ifdef DEBUG_MODE + MessageBoxW (0, L"lock acquired", L"write", 0); +#endif + + Events[0] = dev->ReadEvent; + Events[1] = dev->AbortEvent; + + if (dev->Aborting) + /* this device is long gone */ + return (DWORD)-1; + + if (dev->OpenCount == 0) + /* weird */ + return (DWORD)-1; + + /* According to MSDN, attempting to read from a pipe without writers, + generates a broken pipe error, but the opposite isn't forbidden, so we + allow writing to a pipe without a reader. */ + + DWORD wrote = dev->writeBytes (pBuffer, dwCount); + pBuffer += wrote; + dwCount -= wrote; + + /* According to MSDN, a write of 0, also wakes + the reading end of the pipe. */ + PulseEvent (dev->WriteEvent); + + if (dwCount == 0) + break; + + if (breaknext) + break; + } + + switch (WaitForMultipleObjects (2, Events, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + breaknext = TRUE; + break; + default: + // MessageBoxW (0, L"pipe aborted", L"Write", 0); + /* With either wait error or AbortEvent + signaled, return with error. */ + return (DWORD) -1; + } + } + while (dwCount); + + return needed - dwCount; +} + +PIPEDEV_API DWORD +Seek (PipeOpenContext* /*pOpenContext*/, long /*Amount*/, WORD /*wType*/) +{ + LOGSCOPE ("Seek"); + /* Pipes don't support seeking. */ + return (DWORD)-1; +} + +PIPEDEV_API BOOL +IOControl (PipeOpenContext* pOpenContext, DWORD dwCode, + PBYTE pBufIn, DWORD dwLenIn, + PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) +{ + LOGSCOPE ("IOControl"); + + /* Kill unused warnings. */ + (void)pBufIn; + (void)dwLenIn; + (void)pBufOut; + (void)dwLenOut; + (void)pdwActualOut; + + BOOL bRet = FALSE; + + if (pOpenContext == NULL) + return FALSE; + + PipeDeviceContext* dev = pOpenContext->DeviceContext; + PipeDeviceContext::LockGuard guard G(*dev); + +#ifdef DEBUG_MODE + wchar_t buf[100]; + wsprintf (buf, L"%x : %d", dwCode, dev->OpenCount); + MessageBoxW (0, buf, L"IOControl", 0); +#endif + + if (dwCode == IOCTL_PSL_NOTIFY) + { + PDEVICE_PSL_NOTIFY pPslPacket = (PDEVICE_PSL_NOTIFY)pBufIn; + + if (pPslPacket->dwSize == sizeof (DEVICE_PSL_NOTIFY) + && pPslPacket->dwFlags == DLL_PROCESS_EXITING) + { +#ifdef DEBUG_MODE + WCHAR buf[100]; + wsprintf (buf, L"%p : %p", pPslPacket->hProc, pPslPacket->hThread); + MessageBoxW(0, buf, L"process dying", 0); +#endif + dev->Aborting = TRUE; + /* Unlock all blocked threads. */ + SetEvent (dev->AbortEvent); + } + return TRUE; + } + + switch (dwCode) + { + case PIPE_IOCTL_SET_PIPE_NAME: + if (dev->DeviceName) + free (dev->DeviceName); + dev->DeviceName = wcsdup ((WCHAR*)pBufIn); + bRet = TRUE; + break; + case PIPE_IOCTL_GET_PIPE_NAME: + wcscpy ( (WCHAR*)pBufOut, dev->DeviceName); + *pdwActualOut = (wcslen (dev->DeviceName) + 1) * sizeof (WCHAR); + bRet = TRUE; + break; + } + + return bRet; +} + +PIPEDEV_API void +PowerDown (PipeDeviceContext* /*pDeviceContext*/) +{ +} + +PIPEDEV_API void +PowerUp (PipeDeviceContext* /*pDeviceContext*/) +{ +} Property changes on: trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.cpp ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.h =================================================================== --- trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.h (rev 0) +++ trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.h 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,41 @@ +/* Copyright (c) 2007, Pedro Alves + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#ifndef __PIPEDEVICE_H__ +#define __PIPEDEVICE_H__ + +#include <windows.h> +#include <winioctl.h> + +#define PIPE_IOCTL_SET_PIPE_NAME \ + CTL_CODE(FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define PIPE_IOCTL_GET_PIPE_NAME \ + CTL_CODE(FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define DEVICE_DLL_NAME L"PipeDev.dll" + +#endif Property changes on: trunk/cegcc/tools/PipeLib/PipeDev/PipeDevice.h ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/PipeLib/Makefile =================================================================== --- trunk/cegcc/tools/PipeLib/PipeLib/Makefile (rev 0) +++ trunk/cegcc/tools/PipeLib/PipeLib/Makefile 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,22 @@ +TARGET=arm-wince-mingw32ce + +CXX=$(TARGET)-g++ +AR=$(TARGET)-ar + +INCLUDES=-I../PipeDev/ + +ALLFLAGS=$(INCLUDES) $(CXXFLAGS) + +all: libPipeLib.a + +PipeLib.o: PipeLib.cpp + $(CXX) $< -c -o $@ $(ALLFLAGS) + +libPipeLib.a: PipeLib.o + rm -f $@ + $(AR) r $@ $< + +clean: + rm -f libPipeLib.a PipeLib.o + +.PHONE: all clean Property changes on: trunk/cegcc/tools/PipeLib/PipeLib/Makefile ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.cpp =================================================================== --- trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.cpp (rev 0) +++ trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.cpp 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,218 @@ +/* Copyright (c) 2007, Pedro Alves + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include <PipeDevice.h> + +#include <windows.h> +#include <devload.h> +#include <stdlib.h> + +#define KEY_NAME_BASE L"PipeDevice_" +#define NAME_BASE L"PD" /* Pipe Device */ +#define MAX_INSTANCES 99 + +#if 0 + +/* Doesn't work on CE < 5 ... */ +static int +FindFreeInstanceIndex (void) +{ + HANDLE h; + DEVMGR_DEVICE_INFORMATION di; + WCHAR wzName[6]; + for (int i=0; i < MAX_INSTANCES; i++) + { + wsprintf (wzName, L"%s%02d:", NAME_BASE, i); + di.dwSize = sizeof (di); + h = FindFirstDevice (DeviceSearchByLegacyName, wzName, &di); + if (h == INVALID_HANDLE_VALUE) + return i; + CloseHandle (h); + } + return -1; +} +#endif + +static void +PrepareRegistryForInstance (DWORD dwIndex, WCHAR** wzKey) +{ + DWORD dw; + HKEY hk; + WCHAR szKeyName[255]; + WCHAR wzPrefix[4]; //3 letter + zero character + DWORD dwDisp; + swprintf (wzPrefix, L"%s%d", NAME_BASE, dwIndex / 10); + + swprintf (szKeyName, L"Drivers\\%s%d", KEY_NAME_BASE, dwIndex); + *wzKey = wcsdup (szKeyName); + + if (ERROR_SUCCESS != RegCreateKeyEx (HKEY_LOCAL_MACHINE, + szKeyName, 0, NULL, 0, + KEY_WRITE, NULL, &hk, &dwDisp)) + { + wprintf (L"Failed to create registry key %s, error = %d\n", + szKeyName, (int) GetLastError ()); + return; + } + + RegSetValueEx (hk, L"dll", 0, REG_SZ, (BYTE *)DEVICE_DLL_NAME, + sizeof (DEVICE_DLL_NAME)); + RegSetValueEx (hk, L"prefix", 0, REG_SZ, (BYTE *)wzPrefix, + sizeof (wzPrefix)); + + dw = dwIndex % 10; + RegSetValueEx (hk, L"index", 0, REG_DWORD, (BYTE *)&dw, sizeof (dw)); + + dw = DEVFLAGS_LOADLIBRARY | DEVFLAGS_NAKEDENTRIES; + RegSetValueEx (hk, L"Flags", 0, REG_DWORD, (BYTE *)&dw, sizeof (dw)); + + RegCloseKey (hk); +} + +static BOOL +SetPipeName (HANDLE p, WCHAR* name) +{ + if (!DeviceIoControl (p, PIPE_IOCTL_SET_PIPE_NAME, + (LPVOID) name, (wcslen (name) + 1) * sizeof (WCHAR), + NULL, 0, NULL, NULL)) + return FALSE; + return TRUE; +} + +extern "C" BOOL +GetPipeName (HANDLE p, WCHAR* name) +{ + DWORD actual; + if (!DeviceIoControl (p, PIPE_IOCTL_GET_PIPE_NAME, + NULL, 0, + (LPVOID)name, MAX_PATH * sizeof (WCHAR), + &actual, NULL)) + return FALSE; + return TRUE; +} + +extern "C" BOOL +CreatePipe (PHANDLE hReadPipe, + PHANDLE hWritePipe, + LPSECURITY_ATTRIBUTES lpPipeAttributes, + DWORD nSize) +{ + int inst; + WCHAR* wsKey; + HANDLE h; + + *hReadPipe = NULL; + *hWritePipe = NULL; + + for (inst = 0 ; inst < MAX_INSTANCES; inst++) + { + PrepareRegistryForInstance (inst, &wsKey); + h = ActivateDevice (wsKey, 0); + RegDeleteKey (HKEY_LOCAL_MACHINE, wsKey); + free (wsKey); + + /* Although MSDN documentcs that error should + return INVALID_HANDLE_VALUE, I see it returning + NULL here. */ + if (h != INVALID_HANDLE_VALUE && h != NULL) + break; + } + + if (inst == MAX_INSTANCES) + return FALSE; + + /* name + num + ':' + '0' */ + wchar_t device_name[(sizeof (NAME_BASE) - 1) + 2 + 1 + 1]; + wsprintf (device_name, L"%s%02d:", NAME_BASE, inst); + + *hReadPipe = CreateFile (device_name, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + SetPipeName (*hReadPipe, device_name); + + *hWritePipe = CreateFile (device_name, + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + return TRUE; +} + +#if 0 + +struct PeekStruct +{ + DWORD Size; /* for future extension */ + PVOID lpBuffer, + DWORD nBufferSize, + + /* TODO: We need to use MapPtr for this to work */ + LPDWORD lpBytesRead, + LPDWORD lpTotalBytesAvail, + LPDWORD lpBytesLeftThisMessage + }; + +BOOL +PeekNamedPipe (HANDLE hNamedPipe, + LPVOID lpBuffer, + DWORD nBufferSize, + LPDWORD lpBytesRead, + LPDWORD lpTotalBytesAvail, + LPDWORD lpBytesLeftThisMessage + ) +{ + DWORD avail; + DWORD actual; + + PeekStruct data; + data.Size = sizeof (PeekStruct); + data.lpBuffer = lpBuffer; + data.nBufferSize = nBufferSize; + data.lpBytesRead = lpBytesRead; + data.lpTotalBytesAvail = lpTotalBytesAvail; + data.lpBytesLeftThisMessage = lpBytesLeftThisMessage; + + if (!DeviceIoControl (hNamedPipe, PIPE_IOCTRL_PEEK_NAMED_PIPE, + NULL, 0, + (LPVOID)&data, sizeof (PeekStruct), &actual, NULL)) + return FALSE; + + /* We can detect here if we are talking to an older driver. */ + if (actual != data.Size) + return FALSE; + + return FALSE; +} + +#endif Property changes on: trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.cpp ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.h =================================================================== --- trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.h (rev 0) +++ trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.h 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,43 @@ +/* Copyright (c) 2007, Pedro Alves + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#ifndef __PIPE_LIB_H__ +#define __PIPE_LIB_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +BOOL CreatePipe (PHANDLE,PHANDLE,LPSECURITY_ATTRIBUTES,DWORD); +BOOL GetPipeName (HANDLE, WCHAR*); + +#ifdef __cplusplus +} +#endif + + +#endif Property changes on: trunk/cegcc/tools/PipeLib/PipeLib/PipeLib.h ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/PipeTest/Makefile =================================================================== --- trunk/cegcc/tools/PipeLib/PipeTest/Makefile (rev 0) +++ trunk/cegcc/tools/PipeLib/PipeTest/Makefile 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,21 @@ +TARGET=arm-wince-mingw32ce + +CXX=$(TARGET)-g++ +AR=$(TARGET)-ar + +WARNFLAGS=-Wall -Wextra + +INCLUDES=-I../PipeLib +LIBS=-L../PipeLib -lPipeLib + +ALLFLAGS=$(INCLUDES) $(CXXFLAGS) $(WARNFLAGS) + +all: PipeTest.exe + +PipeTest.exe: PipeTest.cpp Makefile + $(CXX) $< -o $@ $(ALLFLAGS) $(LIBS) $(LDFLAGS) + +clean: + rm -f PipeTest.exe + +.PHONE: all clean Property changes on: trunk/cegcc/tools/PipeLib/PipeTest/Makefile ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/PipeTest/PipeTest.cpp =================================================================== --- trunk/cegcc/tools/PipeLib/PipeTest/PipeTest.cpp (rev 0) +++ trunk/cegcc/tools/PipeLib/PipeTest/PipeTest.cpp 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,172 @@ +/* Copyright (c) 2007, Pedro Alves + * Permission to use, copy, modify, and distribute this software + * is freely granted, provided that this notice is preserved. + */ + +#include <windows.h> +#include <commctrl.h> + +#include <PipeLib.h> + +extern "C" BOOL GetStdioPathW(int, wchar_t*, DWORD*); +extern "C" BOOL SetStdioPathW(int, const wchar_t*); + +volatile BOOL stop = 0; + +static HANDLE readh[3]; +static HANDLE writeh[3]; + +static DWORD WINAPI +stdin_thread (void*) +{ + /* We don't need the reading side. */ + CloseHandle (readh[0]); + readh[0] = INVALID_HANDLE_VALUE; + + while (!stop) + { + DWORD read = 0; + char buf[1]; + + if (!ReadFile ((HANDLE) fileno (stdin), buf, sizeof (buf), &read, FALSE)) + { + OutputDebugStringW (L"stdin: broken pipe\n"); + break; + } + + if (read) + { + DWORD written = 0; + WriteFile (writeh[0], buf, read, &written, NULL); + } + } + + OutputDebugStringW(L"stdin thread gone\n"); + return 0; +} + +static DWORD WINAPI +stdout_thread (void*) +{ + /* We can't close the write side of the pipe until the + child opens its version. Since it will only be open on the + first stdout access, we have to wait until the read side returns + something - which means the child opened stdout. */ + + while (!stop) + { + DWORD read = 0; + char buf[1]; + if (!ReadFile (readh[1], buf, sizeof (buf), &read, FALSE)) + { + OutputDebugStringW (L"stout: broken pipe\n"); + break; + } + else if (writeh[1] != INVALID_HANDLE_VALUE) + { + /* We can now close our wr side. */ + CloseHandle (writeh[1]); + writeh[1] = INVALID_HANDLE_VALUE; + + } + if (read) + { + DWORD written = 0; + WriteFile ((HANDLE) fileno (stdout), buf, read, &written, NULL); + } + } + OutputDebugStringW(L"stdout thread gone\n"); + return 0; +} + + +void +create_inferior (const wchar_t *command, wchar_t** /* child_argv */) +{ + PROCESS_INFORMATION processInfo; + wchar_t prev_path[3][MAX_PATH]; + BOOL bRet; + + for (size_t i = 0; i < 3; i++) + { + wchar_t devname[MAX_PATH]; + if (!CreatePipe (&readh[i], &writeh[i], NULL, 0)) + return; + +#if 0 + CloseHandle (readh[i]); + CloseHandle (writeh[i]); + continue; +#endif + + GetPipeName (readh[i], devname); + DWORD dwLen = MAX_PATH; + GetStdioPathW (i, prev_path[i], &dwLen); + SetStdioPathW (i, devname); + } + + bRet = CreateProcess (command, L"", NULL, NULL, FALSE, 0, + NULL, NULL, NULL, &processInfo); + + if (!bRet) + return; + + for (size_t i = 0; i < 3; i++) + { + SetStdioPathW (i, prev_path[i]); + } + + HANDLE h[3]; + h[0] = CreateThread (NULL, 0, stdin_thread, NULL, 0, NULL); + h[1] = CreateThread (NULL, 0, stdout_thread, NULL, 0, NULL); + h[2] = processInfo.hProcess; + + switch (WaitForMultipleObjects (sizeof (h) / sizeof (h[0]), h, + FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + stop = 1; + TerminateProcess (processInfo.hProcess, 0); + break; + case WAIT_OBJECT_0 + 1: + stop = 1; + TerminateProcess (processInfo.hProcess, 0); + break; + case WAIT_OBJECT_0 + 2: + stop = 1; + + // CloseHandle ((HANDLE) fileno (stdin)); + // TerminateThread (h[0], 0); + // TerminateThread (h[1], 0); + break; + default: + break; + } + + CloseHandle (h[0]); + CloseHandle (h[1]); + CloseHandle (processInfo.hProcess); + CloseHandle (processInfo.hThread); + for (int i = 0; i < 3; i++) + { + CloseHandle (writeh[i]); + } + + for (int i = 0; i < 3; i++) + { + CloseHandle (readh[i]); + } + return; +} + +int WINAPI +WinMain (HINSTANCE /*hInstance*/, + HINSTANCE /*hPrevInstance*/, + LPTSTR /*lpCmdLine*/, + int /*nCmdShow*/) +{ + wchar_t* child_argv[3] = {0}; + + create_inferior (L"TestClient.exe", child_argv); + return 0; +} Property changes on: trunk/cegcc/tools/PipeLib/PipeTest/PipeTest.cpp ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/TestClient/Makefile =================================================================== --- trunk/cegcc/tools/PipeLib/TestClient/Makefile (rev 0) +++ trunk/cegcc/tools/PipeLib/TestClient/Makefile 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,21 @@ +TARGET=arm-wince-mingw32ce + +CXX=$(TARGET)-g++ +AR=$(TARGET)-ar + +WARNFLAGS=-Wall -Wextra + +INCLUDES= +LIBS= + +ALLFLAGS=$(INCLUDES) $(CXXFLAGS) $(WARNFLAGS) + +all: TestClient.exe + +TestClient.exe: TestClient.cpp Makefile + $(CXX) $< -o $@ $(ALLFLAGS) $(LIBS) $(LDFLAGS) + +clean: + rm -f TestClient.exe + +.PHONE: all clean Property changes on: trunk/cegcc/tools/PipeLib/TestClient/Makefile ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/PipeLib/TestClient/TestClient.cpp =================================================================== --- trunk/cegcc/tools/PipeLib/TestClient/TestClient.cpp (rev 0) +++ trunk/cegcc/tools/PipeLib/TestClient/TestClient.cpp 2007-06-09 17:47:55 UTC (rev 934) @@ -0,0 +1,20 @@ +#include <windows.h> + +int WINAPI WinMain(HINSTANCE /*hInstance*/, + HINSTANCE /*hPrevInstance*/, + LPTSTR /*lpCmdLine*/, + int /*nCmdShow*/) +{ + int count = 0; + + for (int i = 0; i < 10; i++) + { + printf ("count = %d\n", count++); + Sleep (1000); + } + + // DWORD* zero = 0; + // return *zero; + + return 0; +} Property changes on: trunk/cegcc/tools/PipeLib/TestClient/TestClient.cpp ___________________________________________________________________ Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |