sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // C routines for creating EPOC32 threads
sl@0: // 
sl@0: //
sl@0: 
sl@0: #include <e32std.h>
sl@0: #include <estlib.h>		/* for SpawnPosixServerThread */
sl@0: #include <unistd.h>
sl@0: #include <stdio.h>		/* for popen3 */
sl@0: #include <stdlib.h>		/* for mbstowcs */
sl@0: #include "CTEST.H"
sl@0: #include <sys/errno.h>		/* for errno */
sl@0: #include <sys/wait.h>
sl@0: 
sl@0: typedef void (*FUNC)();
sl@0: 
sl@0: struct cthread 
sl@0: {
sl@0: 	RThread iThread;
sl@0: 	RProcess iProcess;
sl@0: 	TRequestStatus iStatus;
sl@0: 	int pid;
sl@0: };
sl@0: 
sl@0: TInt threadhelper (TAny* aFn)
sl@0: 	{
sl@0: 	CTrapCleanup::New();
sl@0: 	FUNC f=(FUNC)aFn;
sl@0: 	(*f)();
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: #if defined(__WINS__)
sl@0: 
sl@0: IMPORT_C void NewProcessId();		// WINS bodges for multiple "processes"
sl@0: IMPORT_C void NextProcessFn(TAny*);	
sl@0: 
sl@0: TInt processhelper (TAny* aFn)
sl@0: 	{
sl@0: 	// Do the MCRT0.OBJ things straight away
sl@0: 	NewProcessId();
sl@0: 	SpawnPosixServerThread();
sl@0: 	char wd[80];
sl@0: 	getcwd(wd, sizeof(wd));		// connect to CPosixServer
sl@0: 	return threadhelper(aFn);
sl@0: 	}
sl@0: 
sl@0: #endif //__WINS__
sl@0: 
sl@0: 
sl@0: extern "C" {
sl@0: 
sl@0: EXPORT_C int start_posix_server()
sl@0: 	{
sl@0: 	start_redirection_server();
sl@0: 	return SpawnPosixServerThread();
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void* create_thread(void (*aFn)(), char* aName)
sl@0: 	{
sl@0: #ifdef _UNICODE
sl@0: 	TPtrC8 ptr((TText8*)aName);
sl@0: 	TBuf<80> name;
sl@0: 	name.Copy(ptr);
sl@0: #else
sl@0: 	TPtrC8 name((TText8*)aName);
sl@0: #endif /* _UNICODE */
sl@0: 	struct cthread* t = new cthread;
sl@0: 	// 16k stack, share parent's heap
sl@0: 	TInt err=t->iThread.Create(name, threadhelper, 0x4000, NULL, (TAny*)aFn);
sl@0: 	t->iThread.Logon(t->iStatus);
sl@0: 	if (err!= KErrNone)
sl@0: 		return 0;
sl@0: 	return (void*)t;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void start_thread(void* aThread)
sl@0: 	{
sl@0: 	struct cthread* t=REINTERPRET_CAST(struct cthread*,aThread);
sl@0: 	t->iThread.Resume();
sl@0: 	}
sl@0: 
sl@0: EXPORT_C int wait_for_thread(void* aThread)
sl@0: 	{
sl@0: 	struct cthread* t=REINTERPRET_CAST(struct cthread*,aThread);
sl@0: 	User::WaitForRequest(t->iStatus);
sl@0: 	int ret=t->iThread.ExitReason();
sl@0: 	t->iThread.Close();
sl@0: 	delete t;
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void* create_process(void (*aFn)(), char* aName, char* mode, int fids[3])
sl@0: 	{
sl@0: #ifdef _UNICODE
sl@0: 	TPtrC8 ptr((TText8*)aName);
sl@0: 	TBuf<80> name;
sl@0: 	name.Copy(ptr);
sl@0: #else
sl@0: 	TPtrC8 name((TText8*)aName);
sl@0: #endif /* _UNICODE */
sl@0: 	struct cthread* t = new cthread;
sl@0: 	TFileName this_exe = t->iProcess.FileName();
sl@0: 	TBuf<256> cmd;
sl@0: 	cmd.Format(_L("%S %S"),&this_exe,&name);
sl@0: 	cmd.ZeroTerminate();
sl@0: 
sl@0: #ifdef _UNICODE
sl@0: 	wchar_t wmode[MAXPATHLEN+1];
sl@0: 	mbstowcs(wmode, mode, MAXPATHLEN);
sl@0: 	t->pid=wpopen3((const wchar_t*)cmd.Ptr(), wmode, 0, fids);
sl@0: #else
sl@0: 	t->pid=popen3((const char*)cmd.Ptr(), mode, 0, fids);
sl@0: #endif
sl@0: 	if (t->pid < 0)
sl@0: 		return 0;
sl@0: 	User::After(1000000); // 1 Second
sl@0: 	return (void*)t;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void start_process(void* /*aProcess*/)
sl@0: 	{
sl@0: 	// too late, it's already running!
sl@0: 	}
sl@0: 
sl@0: EXPORT_C int wait_for_process(void* aProcess)
sl@0: 	{
sl@0: 	struct cthread* t=REINTERPRET_CAST(struct cthread*,aProcess);
sl@0: 	int exit=-1;
sl@0: 	int pid=waitpid(t->pid, &exit, 0);
sl@0: 	if (pid<0)
sl@0: 		return errno;
sl@0: 	return exit;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C int wait_for_process_id(void* aProcess, int procid, int opt, int* status)
sl@0: 	{
sl@0: 	// added function to enable calling of waitpid with specific parameters
sl@0: 	int pid=waitpid(procid, status, opt);
sl@0: 	return pid;
sl@0: 	}
sl@0: 	
sl@0: EXPORT_C int get_proc_id(void* aProcess)
sl@0: 	{
sl@0: 	// return the pid of a process
sl@0: 	struct cthread* t=REINTERPRET_CAST(struct cthread*,aProcess);
sl@0: 	return t->pid;
sl@0: 	}
sl@0: 
sl@0: // Testing the dodgy asynchronous form of select
sl@0: 
sl@0: EXPORT_C int async_ioctl(int aFid, int aCmd, void* aParam, int* status)
sl@0: 	{
sl@0: 	TRequestStatus& theStatus = *(TRequestStatus*)status;
sl@0: 	return ioctl(aFid,aCmd,aParam,theStatus);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C int async_ioctl_completion(int aFid, int aCmd, void* aParam, int* status)
sl@0: 	{
sl@0: 	TRequestStatus& theStatus = *(TRequestStatus*)status;
sl@0: 	User::WaitForRequest(theStatus);
sl@0: 	return ioctl_complete(aFid,aCmd,aParam,theStatus);
sl@0: 	}
sl@0: 
sl@0: } // extern "C"