Author Topic: ScriptBasic IUP - (multi-threaded)  (Read 3317 times)

Offline John

  • Forum Support / SB Dev
  • Posts: 2999
    • ScriptBasic Open Source Project
ScriptBasic IUP - (multi-threaded)
« on: January 20, 2014, 08:27:38 PM »
It's been awhile since I talked about ScriptBasic. Working with Richard and BBC4W reminded me of a similar demo I used to show how SB and IUP can run in a multi-threaded environment even though IUP isn't thread safe.







Thread #1 script
Code: [Select]
' Thread #1 Script

INCLUDE "dllcinc.sb"

iup = dllfile("iup.dll")

IupOpen          = dllproc(iup,"IupOpen          cdecl i = (i argc, i argv)")
IupCreate        = dllproc(iup,"IupCreate        cdecl i = (c *classname)")
IupSetAttributes = dllproc(iup,"IupSetAttributes cdecl i = (i ih, c *attr_str)")
IupAppend        = dllproc(iup,"IupAppend        cdecl i = (i ih, cdecl i new_child)")
IupSetCallback   = dllproc(iup,"IupSetCallback   cdecl i = (i ih, c*cb_name, i funcaddr)")
IupShow          = dllproc(iup,"IupShow          cdecl i = (i ih)")
IupMainLoop      = dllproc(iup,"IupMainLoop      cdecl i = ()")
IupClose         = dllproc(iup,"IupClose         cdecl     ()")

GLOBAL CONST IUP_DEFAULT = -2

FUNCTION Btn1_T1(ih, mbut, pstat)
  PRINT "B1 - T1 ", CHR(mbut), " - ", pstat, "\n"
  Btn1_clicked = IUP_DEFAULT
END FUNCTION

FUNCTION Btn2_T1(ih)
  dllprnt"B2 - T1\n"
  Btn2_clicked = IUP_DEFAULT
END FUNCTION

FUNCTION Btn3_T1(ih)
  dllprnt"B3 - T1\n"
  Btn3_clicked = IUP_DEFAULT
END FUNCTION

FUNCTION main(pProg,idat)
  dllcall(IupOpen, 0, 0)
  win = dllcall(IupCreate, "dialog")
  dllcall(IupSetAttributes, win, "TITLE=\"Thread #1\", SIZE=300x")
  horzbox = dllcall(IupCreate, "hbox")
  dllcall(IupSetAttributes, horzbox, "GAP=5")
  btn1 = dllcall(IupCreate, "button")
  dllcall(IupSetAttributes, btn1, "TITLE=Button1, EXPAND=HORIZONTAL")
  btn2 = dllcall(IupCreate, "button")
  dllcall(IupSetAttributes, btn2, "TITLE=Button2, EXPAND=HORIZONTAL")
  btn3 = dllcall(IupCreate, "button")
  dllcall(IupSetAttributes, btn3, "TITLE=Button3, EXPAND=HORIZONTAL")
  dllcall(IupAppend, horzbox, btn1)
  dllcall(IupAppend, horzbox, btn2)
  dllcall(IupAppend, horzbox, btn3)
  dllcall(IupAppend, win, horzbox)
  dllcall(IupSetCallback, btn1, "BUTTON_CB", dllclbk(1, pProg, "MAIN::Btn1_T1", 3,IUP_DEFAULT,idat))
  dllcall(IupSetCallback, btn2, "ACTION", dllclbk(2, pProg, "MAIN::Btn2_T1", 1,IUP_DEFAULT,idat))
  dllcall(IupSetCallback, btn3, "ACTION", dllclbk(3, pProg, "MAIN::Btn3_T1", 1,IUP_DEFAULT,idat))
  dllcall(IupShow, win)
  Main=IupMainLoop
END FUNCTION

Thread #2 script
Code: [Select]
' Thread #2 Script

INCLUDE "dllcinc.sb"

iup = dllfile("iup.dll")

IupOpen          = dllproc(iup,"IupOpen          cdecl i = (i argc, i argv)")
IupCreate        = dllproc(iup,"IupCreate        cdecl i = (c *classname)")
IupSetAttributes = dllproc(iup,"IupSetAttributes cdecl i = (i ih, c *attr_str)")
IupAppend        = dllproc(iup,"IupAppend        cdecl i = (i ih, cdecl i new_child)")
IupSetCallback   = dllproc(iup,"IupSetCallback   cdecl i = (i ih, c*cb_name, i funcaddr)")
IupShow          = dllproc(iup,"IupShow          cdecl i = (i ih)")
IupMainLoop      = dllproc(iup,"IupMainLoop      cdecl i = ()")
IupClose         = dllproc(iup,"IupClose         cdecl     ()")

GLOBAL CONST IUP_DEFAULT = -2

FUNCTION Btn1_T2(ih)
  dllprnt"B1 - T2\n"
  Btn1_clicked = IUP_DEFAULT
END FUNCTION

FUNCTION Btn2_T2(ih)
  dllprnt"B2 - T2\n"
  Btn2_clicked = IUP_DEFAULT
END FUNCTION

FUNCTION Btn3_T2(ih)
  dllprnt"B3 - T2\n"
  Btn3_clicked = IUP_DEFAULT
END FUNCTION

FUNCTION main(pProg,idat)
  dllcall(IupOpen, 0, 0)
  win = dllcall(IupCreate, "dialog")
  dllcall(IupSetAttributes, win, "TITLE=\"Thread #2\", SIZE=300x")
  horzbox = dllcall(IupCreate, "hbox")
  dllcall(IupSetAttributes, horzbox, "GAP=5")
  btn1 = dllcall(IupCreate, "button")
  dllcall(IupSetAttributes, btn1, "TITLE=Button1, EXPAND=HORIZONTAL")
  btn2 = dllcall(IupCreate, "button")
  dllcall(IupSetAttributes, btn2, "TITLE=Button2, EXPAND=HORIZONTAL")
  btn3 = dllcall(IupCreate, "button")
  dllcall(IupSetAttributes, btn3, "TITLE=Button3, EXPAND=HORIZONTAL")
  dllcall(IupAppend, horzbox, btn1)
  dllcall(IupAppend, horzbox, btn2)
  dllcall(IupAppend, horzbox, btn3)
  dllcall(IupAppend, win, horzbox)
  dllcall(IupSetCallback, btn1, "ACTION", dllclbk(4, pProg, "MAIN::Btn1_T2", 1,IUP_DEFAULT,idat))
  dllcall(IupSetCallback, btn2, "ACTION", dllclbk(5, pProg, "MAIN::Btn2_T2", 1,IUP_DEFAULT,idat))
  dllcall(IupSetCallback, btn3, "ACTION", dllclbk(6, pProg, "MAIN::Btn3_T2", 1,IUP_DEFAULT,idat))
  dllcall(IupShow, win)
  Main=IupMainLoop
END FUNCTION

Start script
Code: [Select]
' Boot (Main / Launcher)

INCLUDE "dllcinc.sb"
bdat=string(8192,chr(0))
idat=dllsptr(bdat)

thrM1 = dlltran("T1.sb","main::main",1,idat)
thrM2 = dlltran("T2.sb","main::main",2,idat)

LINE INPUT wait

dllclos thrM1,thrM2
dllfile

Charles's DLLC extension module for ScriptBasic Windows allows calling a function in a DLL as an independent thread as well. ScriptBasic doesn't support COM automation (yet) but does support low level direct COM (vtable) access. Another nice feature DLLC offers is a JIT O2 virtual DLL option as I call it. Within SB I can create a string that contains source to an OxygenBasic function. I can compile the function and call it as if I loaded it from a DLL.

If Charles finds time maybe he can expand on the DLLC extension module topic and tell us about it's future plans.

MS COM SAPI example
Code: [Select]
'DECLARING PROCEDURES

stringbuf        = dllproc(mylib,"stringbuf stdcall i=(c*buf, i bufsize) " )
doublebyref      = dllproc(mylib,"doublebyref (d*num)"           )
longbyref        = dllproc(mylib,"longbyref (l*num)"             )
returnbstring    = dllproc(mylib,"returnbstring o=()"            )
rectanglearea    = dllproc(mylib,"rectanglearea i=(t*rectangle)" )
showguid         = dllproc(mylib,"showguid z=(t*guidinput,t*guidinput)"      )

CoInitialize     = dllproc(ole32,"CoInitialize (i)")
CoUninitialize   = dllproc(ole32,"CoUninitialize (i)")
CoCreateInstance = dllproc(ole32,"CoCreateInstance i=(t*ObjGuid ,i pUnkOuter,i context, t*IspGuid, i*Iface)" )

'COM SPEECH

VoiceObjGuid = dllguid("96749377-3391-11D2-9EE3-00C04F797396")
ISpVoiceGuid = dllguid("6C44DF74-72B9-4992-A1EC-EF996E0422D4")
Context      = 7
pUnkOuter    = 0
Voice        = 0
Release      = dllmeth( 2,"Release i=()")
Speak        = dllmeth(20,"Speak i=(z*pwcs,i flags,i pulstreamno)")
WaitUntilDone= dllmeth(32,"WaitUntilDone i=(i)")
print dllreco(speak)
Text         = dllwstr("Hello Everyone!\0")
hr=0
dllcall(CoInitialize,0)
hr=dllcall(CoCreateInstance, VoiceObjGuid, pUnkouter, Context, ISpVoiceGuid, Voice)
if (hr=0) then
  print "connected to voice\n\n"
  print dllastr(Text) & "\n\n"
  dllcobj(Voice,Speak,Text,0,0)
  dllcobj(Voice,WaitUntilDone,0xFFFFFFFF)
  dllcobj(Voice,Release)
else
  print "SAPI Error " & format("%x",hr) & "\n\n"
end if
dllcall(CoUninitialize)

Use and distribution options

ScriptBasic has 4 ways you can run and distribute your code.

  • Use scriba from a console/terminal as a command line BASIC interpreter. (stdin/out/err redirection supported)
  • Use the scriba -E option which attaches a binary (compiled) form of your main/included scripts and appends it to the end of a copy of scriba. Scriiba always checks to see if a script is attached before processing any command line argument. This adds about 460KB to your standalone program
  • Use the scriba -C option which converts the user script to a C source program. With this option extension modules can be static linked. A Hello World compiled SB script is about 12 KB.
  • ScriptBasic was developed as an embeddable scripting API as it's intended purpose. Scriba was an example of how to use the SB API and took on a life of of it's own as did the multi-threaded HTTPD application server that was written to show the thread safe features.

FYI ScriptBasic also offers a single threaded standard IUP extension module which is based on one C source version for all platforms. ScriptBasic applications using this method allows the same script to run untouched on all platforms.
« Last Edit: January 21, 2014, 09:46:52 AM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 2999
    • ScriptBasic Open Source Project
Re: ScriptBasic IUP - (multi-threaded)
« Reply #1 on: January 21, 2014, 11:09:12 AM »
Here is the above Wine example running on Windows 7. I'm using a form of scriba that was compiled as a Windows application rather than a console mode app. I also included XP theme support into the build. If a Windows association for .sb is enabled, clicking on IUP based SB scripts will start the application in GUI mode without any console. Charles created a console option in DLLC that can be enable for debugging while using the Windows GUI version SB.







This is a screen shot of an example I did for one of my clients that is looking for a way port their ProvideX Business Basic NOMADS applications to a multi-platform environment. Sage got sold a line of BS and converted their business logic to an OOP simulated environment. The result is that it runs 5X slower and is almost unusable. The goal was to to reuse code and ended up making it almost impossible to modify and support. I was able to demonstrate a commonly used object instantiated 1000 times in less than a second running under ScriptBasic. Sage is trying to kill the product line and move the customer base to other more profitable shrink wrap solutions. My goal for this quarter is to provide a set of tools that will allow ProvideX users a sane option moving forward without a complete lost of their investments.

« Last Edit: January 21, 2014, 11:58:24 AM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 2999
    • ScriptBasic Open Source Project
Re: ScriptBasic IUP - (multi-threaded)
« Reply #2 on: January 21, 2014, 03:33:35 PM »
I forgot to mention that ScriptBasic's MT extension module that is used in the sbhttpd multi-threaded web server for session and shared variables support works fine with the DLLC multi-threading environment.

Thread #1 changes (set MT variable as the first line of code in the main function of the script)
Code: [Select]
IMPORT mt.bas
mt::SetVariable("tvar", "John")

Thread #2 changes (dllprnt"B1 - T2\n"  replaced with code below in Button 1 print to console when clicked)
Code: [Select]
IMPORT mt.bas
dllprnt(mt::GetVariable("tvar")),"\n"

C:\scriptbasic\iupmt>scriba tboot.sb
B1 - T1 1 - 1
B1 - T1 1 - 0
John

C:\scriptbasic\iupmt>

« Last Edit: January 21, 2014, 04:27:42 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 2999
    • ScriptBasic Open Source Project
Re: ScriptBasic IUP
« Reply #3 on: January 23, 2014, 12:10:46 AM »
Here is an example of the ScriptBasic multi-platform version of the IUP extension module. (single threaded) The following code was run untouched on both platforms.

Ubuntu 64 bit


Windows XP


Code: [Select]
' IUP Button / Event Example

IMPORT iup.bas

SUB Btn1_clicked
  PRINT "BUTTON 1 Event\n"
END SUB

SUB Btn2_clicked
  PRINT "BUTTON 2 Event\n"
END SUB

SUB Btn3_clicked
  PRINT "BUTTON 3 Event\n"
END SUB

SUB Win_exit
  Iup::ExitLoop = TRUE
END SUB

Iup::Open()
win = Iup::Create("dialog")
Iup::SetAttributes(win, "TITLE=\"Test Dialog\", SIZE=300x")
horzbox = Iup::Create("hbox")
Iup::SetAttributes(horzbox, "GAP=5")
btn1 = Iup::Create("button")
Iup::SetAttributes(btn1, "TITLE=Button1, EXPAND=HORIZONTAL")
btn2 = Iup::Create("button")
Iup::SetAttributes(btn2, "TITLE=Button2, EXPAND=HORIZONTAL")
btn3 = Iup::Create("button")
Iup::SetAttributes(btn3, "TITLE=Button3, EXPAND=HORIZONTAL")
Iup::Append(horzbox, btn1)
Iup::Append(horzbox, btn2)
Iup::Append(horzbox, btn3)
Iup::Append(win, horzbox)
Iup::SetCallback(win,"CLOSE_CB",ADDRESS(Win_exit()))
Iup::SetCallback(btn1,"ACTION",ADDRESS(Btn1_clicked()))
Iup::SetCallback(btn2,"ACTION",ADDRESS(Btn2_clicked()))
Iup::SetCallback(btn3,"ACTION",ADDRESS(Btn3_clicked()))
Iup::Show(win)
Iup::MainLoop()
Iup::Close()

jrs@laptop:~/sb/test$ scriba buttons.sb
BUTTON 1 Event
BUTTON 2 Event
BUTTON 3 Event
jrs@laptop:~/sb/test$

C:\scriptbasic\test>sbiup buttons.sb    <--- Using Windows version SB with XP theme support (non-console)
BUTTON 1 Event
BUTTON 2 Event
BUTTON 3 Event
C:\scriptbasic\test>
« Last Edit: January 23, 2014, 12:20:44 AM by John »