Advertisement

Concurrent example not working under linux

Started by February 23, 2009 03:15 PM
5 comments, last by WitchLord 15 years, 9 months ago
First off, I'm new AngleScript and love'n it! When I got around to trying the "concurrent" example, I saw no output for script "a" or "b". After poking around I found the problem to be with the included linux version of kbhit(). It was getting stuck in there. So after a quick google session I found an alternative version that works good - with GCC anyway. Here's the working version that I found ...Sorry if this is a repost #include <stdio.h> #include <termios.h> #include <unistd.h> #include <fcntl.h> int kbhit( void ) { struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) { ungetc(ch, stdin); return 1; } return 0; }
" In a world without fences and walls, who needs Gates and Windows?"
I ported the examples to Linux originally and I remember all of them functioning properly. When I get a chance I'll see if I get the same issue.
Advertisement
Yeah, the kbhit I had wasn't working correctly, the version you posted works like it should.

Here is the updated source with the above code from GDTheLaw:
#include <iostream>  // cout#include <assert.h>  // assert()#include <vector>#include <angelscript.h>#include "../../../add_on/scriptstring/scriptstring.h"#ifdef _LINUX_ 	#include <sys/time.h>	#include <stdio.h>	#include <termios.h>	#include <unistd.h>	#include <fcntl.h>	#include <string.h>#elif defined(__APPLE__)	#include <curses.h>#else	#include <conio.h>   // kbhit(), getch()	#include <windows.h> // timeGetTime()#endifusing namespace std;#ifdef _LINUX_#define UINT unsigned int typedef unsigned int DWORD;// Linux doesn't have timeGetTime(), this essintially does the same// thing, except this is milliseconds since Epoch (Jan 1st 1970) instead// of system start. It will work the same though...DWORD timeGetTime(){	timeval time;	gettimeofday(&time, NULL);	return time.tv_sec*1000 + time.tv_usec/1000;}// kbhit() for linuxint kbhit() {	struct termios oldt, newt;	int ch;	int oldf;	tcgetattr(STDIN_FILENO, &oldt);	newt = oldt;	newt.c_lflag &= ~(ICANON | ECHO);	tcsetattr(STDIN_FILENO, TCSANOW, &newt);	oldf = fcntl(STDIN_FILENO, F_GETFL, 0);	fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);	ch = getchar();	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);	fcntl(STDIN_FILENO, F_SETFL, oldf);	if(ch != EOF) 	{		ungetc(ch, stdin);		return 1;	}	return 0;}#elif defined(__APPLE__)#define UINT unsigned inttypedef unsigned int DWORD;// Linux doesn't have timeGetTime(), this essintially does the same// thing, except this is milliseconds since Epoch (Jan 1st 1970) instead// of system start. It will work the same though...DWORD timeGetTime(){	timeval time;	gettimeofday(&time, NULL);	return time.tv_sec*1000 + time.tv_usec/1000;}int kbhit(){	if( getch() == ERR )		return 0;			return 1;}#endif// Function prototypesvoid ConfigureEngine(asIScriptEngine *engine);int  CompileScript(asIScriptEngine *engine);void PrintString(string &str);void PrintNumber(int num);void ScriptSleep(UINT milliSeconds);struct SContextInfo{	UINT sleepUntil;	asIScriptContext *ctx;};// This simple manager will let us manage the contexts, // in a simple scheme for apparent multithreadingclass CContextManager{public:	void AddContext(int funcID);	void ExecuteScripts();	void SetSleeping(asIScriptContext *ctx, UINT milliSeconds);	void AbortAll();	vector<SContextInfo> contexts;} contextManager;void MessageCallback(const asSMessageInfo *msg, void *param){	const char *type = "ERR ";	if( msg->type == asMSGTYPE_WARNING ) 		type = "WARN";	else if( msg->type == asMSGTYPE_INFORMATION ) 		type = "INFO";	printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);}asIScriptEngine *engine = 0;int main(int argc, char **argv){	int r;	// Create the script engine	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);	if( engine == 0 )	{		cout << "Failed to create script engine." << endl;		return -1;	}	// The script compiler will send any compiler messages to the callback function	engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);	// Configure the script engine with all the functions, 	// and variables that the script should be able to use.	ConfigureEngine(engine);	// Compile the script code	r = CompileScript(engine);	if( r < 0 ) return -1;	contextManager.AddContext(engine->GetModule("script1")->GetFunctionIdByDecl("void main()"));	contextManager.AddContext(engine->GetModule("script2")->GetFunctionIdByDecl("void main()"));		// Print some useful information and start the input loop	cout << "This sample shows how two scripts can be executed concurrently." << endl; 	cout << "Both scripts voluntarily give up the control by calling Sleep()." << endl;	cout << "Press any key to terminate the application." << endl;	for(;;)	{		// Check if any key was pressed		if( kbhit() )		{			contextManager.AbortAll();			break;		}		// Allow the contextManager to determine which script to execute next		contextManager.ExecuteScripts();	}	// Release the engine	engine->Release();	return 0;}void ConfigureEngine(asIScriptEngine *engine){	int r;	// Register the script string type	// Look at the implementation for this function for more information  	// on how to register a custom string type, and other object types.	// The implementation is in "/add_on/scriptstring/scriptstring.cpp"	RegisterScriptString(engine);	// Register the functions that the scripts will be allowed to use	r = engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString), asCALL_CDECL); assert( r >= 0 );	r = engine->RegisterGlobalFunction("void Print(int)", asFUNCTION(PrintNumber), asCALL_CDECL); assert( r >= 0 );	r = engine->RegisterGlobalFunction("void Sleep(uint)", asFUNCTION(ScriptSleep), asCALL_CDECL); assert( r >= 0 );}int CompileScript(asIScriptEngine *engine){	int r;	// This script prints a message 3 times per second	const char *script1 = 	"int count = 0;                     "	"void main()                        "	"{                                  "    "  for(;;)                          "	"  {                                "	"    Print(\"A :\");                "	"    Print(count++);                "	"    Print(\"\\n\");                "	"    Sleep(333);                    "	"  }                                "	"}                                  ";		// This script prints a message once per second	const char *script2 =	"int count = 0;                     "	"void main()                        "	"{                                  "	"  for(;;)                          "	"  {                                "	"    Print(\" B:\");                "	"    Print(count++);                "	"    Print(\"\\n\");                "	"    Sleep(1000);                   "	"  }                                "	"}                                  ";	// Build the two script into separate modules. This will make them have	// separate namespaces, which allows them to use the same name for functions	// and global variables.	asIScriptModule *mod = engine->GetModule("script1", asGM_ALWAYS_CREATE);	r = mod->AddScriptSection("script1", script1, strlen(script1));	if( r < 0 ) 	{		cout << "AddScriptSection() failed" << endl;		return -1;	}		r = mod->Build();	if( r < 0 )	{		cout << "Build() failed" << endl;		return -1;	}	mod = engine->GetModule("script2", asGM_ALWAYS_CREATE);	r = mod->AddScriptSection("script2", script2, strlen(script2));	if( r < 0 )	{		cout << "AddScriptSection() failed" << endl;		return -1;	}	r = mod->Build();	if( r < 0 )	{		cout << "Build() failed" << endl;		return -1;	}	return 0;}void PrintString(string &str){	cout << str;}void PrintNumber(int num){	cout << num;}void ScriptSleep(UINT milliSeconds){	// Get a pointer to the context that is currently being executed	asIScriptContext *ctx = asGetActiveContext();	if( ctx )	{		// Suspend it's execution. The VM will continue until the current 		// statement is finished and then return from the Execute() method		ctx->Suspend();		// Tell the context manager when the context is to continue execution		contextManager.SetSleeping(ctx, milliSeconds);	}}void CContextManager::ExecuteScripts(){	// Check if the system time is higher than the time set for the contexts	UINT time = timeGetTime();	for( int n = 0; n < (signed)contexts.size(); n++ )	{		if( contexts[n].ctx && contexts[n].sleepUntil < time )		{			int r = contexts[n].ctx->Execute();			if( r != asEXECUTION_SUSPENDED )			{				// The context has terminated execution (for one reason or other)				contexts[n].ctx->Release();				contexts[n].ctx = 0;			}		}	}}void CContextManager::AbortAll(){	// Abort all contexts and release them. The script engine will make 	// sure that all resources held by the scripts are properly released.	for( int n = 0; n < (signed)contexts.size(); n++ )	{		if( contexts[n].ctx )		{			contexts[n].ctx->Abort();			contexts[n].ctx->Release();			contexts[n].ctx = 0;		}	}}void CContextManager::AddContext(int funcID){	// Create the new context	asIScriptContext *ctx = engine->CreateContext();	if( ctx == 0 )	{		cout << "Failed to create context" << endl;		return;	}	// Prepare it to execute the function	int r = ctx->Prepare(funcID);	if( r < 0 )	{		cout << "Failed to prepare the context" << endl;		return;	}	// Add the context to the list for execution	SContextInfo info = {0, ctx};	contexts.push_back(info);}void CContextManager::SetSleeping(asIScriptContext *ctx, UINT milliSeconds){	// Find the context and update the timeStamp  	// for when the context is to be continued	for( int n = 0; n < (signed)contexts.size(); n++ )	{		if( contexts[n].ctx == ctx )		{			contexts[n].sleepUntil = timeGetTime() + milliSeconds;		}	}}
Thanks for the fix. I've checked it into the SVN.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

The same faulty kbhit() is also in other examples like coroutines and events. Just wanted to make sure you got them too. Thanks and keep up the good work!
" In a world without fences and walls, who needs Gates and Windows?"
Ah, yes. I forgot to check that. I'll have those fixed also.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
I've fixed the kbhit function in all three samples that used it. Let me know if there are any other problems.

Thanks,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement