MainThread blocks all others

Nodir Gulyamov gelios at rbcmail.ru
Wed Aug 10 13:12:25 EDT 2005


Hello Dennis and Bryan!
    You were absolutely right. I should show you real code instead of brain 
fucking. I am very sorry.
Please find below real code. Sorry for amount of sources.
Main aspect of program is all process should be in one determined sequence 
containing 3 stages. They are defined as stage1(), stage2() and stage3() in 
appMainFrame()
Execution started when Start button presses (handler def OnStart() in 
appMainFrame() ). At the same time CardsObserver calls 
appMainFrame.addCards() to increment counter and in each stages wait this 
counter.
All other code from library.

Kind regards,
/Gelios

#######################Main application:################################

#exception class
class NotASIMCardException:
    def __init__( self, message ):
        self.message = message
    def __str__(self):
        return repr( self.message )


class SmartCardOperations:

    def getATR( self, readerDescr ):
        atr=""
        self.attachedReaders = readers()
        for reader in self.attachedReaders:
            if readerDescr == str( reader ):
                connection=reader.createConnection()
                try:
                    connection.connect()
                    atr=toHexString( connection.getATR() )
                    connection.disconnect()
                except NoCardException:
                    atr="no card inserted"
        return atr

    def decodeICCID( self, iccidBytes ):
        resIccid = []

        #swap bytes
        i = 0
        while i < len(iccidBytes):
            strTmp = str( hex( iccidBytes[i] ) )
            if len(strTmp) == 3:
                strTmp = strTmp[0] + strTmp[1] + "0" + strTmp[2]
            resIccid += [strTmp[3] + strTmp[2]]
            i += 1

        #remove last 2 bytes
        resIccid = resIccid[:-2]
        #remove first last digit
        strTmp = str( resIccid[i-3] )
        if len(strTmp) == 1:
            strTmp += "0"
        resIccid[i-3] = strTmp[0]

        return resIccid

    def getICCID(self, readerDescr):
        self.attachedReaders = readers()
        for reader in self.attachedReaders:
            if readerDescr == str( reader ):
                session = smartcard.Session( reader )
                try:
                    data, sw1, sw2 = session.sendCommandAPDU( SELECT + 
DF_ROOT )
                    data, sw1, sw2 = session.sendCommandAPDU( SELECT + 
EF_ICCID )
                    data, sw1, sw2 = session.sendCommandAPDU( READ_BINARY + 
[0x0A])
                    if sw1 == 0x90 or sw1 == 0x91:
                        msg = "Ok"
                    else:
                        msg = "ICCID read error. Error code: " + 
str(hex(sw1)) + str(hex(sw2))
                    session.close()
                except NoCardException:
                    msg = "ICCID read error. Error code: " + str(hex(sw1)) + 
str(hex(sw2))

        return msg, self.decodeICCID(data), data

    def getADM0( self, readerDescr, iccid ):
        self.attachedReaders = readers()
        for reader in self.attachedReaders:
            if readerDescr == str( reader ):
                session = smartcard.Session( reader )
                try:
                    data, sw1, sw2 = session.sendCommandAPDU( SAM_SEND_ICCID 
+ iccid )
                    resBytesStr = str(sw1) + ' ' + str(sw2)
                    if resBytesStr != "61 08":
                        msg = "?????? ?????? ? SAM ??????"
                        return msg, None
                    data, sw1, sw2 = session. sendCommandAPDU( 
SAM_GET_ADM0 )
                except NoCardException:
                    msg = "ADM0 getting error. Error code: " + str(hex(sw1)) 
+ str(hex(sw2))
        msg = "Ok"
        return msg, data

    def chgEfLnd( self, iccid, adm0 ):
        self.attachedReaders = readers()
        for reader in self.attachedReaders:
            if readerDescr == str( reader ):
                session = smartcard.Session( reader )
                try:
                    data, sw1, sw2 = session.sendCommandAPDU( 
VERIFY_KEY_SIMERA3 + adm0 )
                    resBytesStr = str(sw1) + ' ' + str(sw2)
                    if resBytesStr == "98 04" or resBytesStr == "98 40":
                        msg = "?????? ??????? ? ?????"
                        return msg
                    data, sw1, sw2 = session.sendCommandAPDU( SELECT + 
DF_ROOT )
                    data, sw1, sw2 = session.sendCommandAPDU( SELECT + 
DF_GSM )
                    data, sw1, sw2 = session.sendCommandAPDU( DELETE_FILE )
                    if sw1 != 0x90 or sw1 != 0x91:
                        msg = "?????? ??????? ? ?????"
                        return msg
                    data, sw1, sw2 = session.sendCommandAPDU( SELECT + 
DF_GSM )
                    data, sw1, sw2 = session.sendCommandAPDU(
                                        smartcard.util.toBytes(CREATE_FILE_APDU)
                    if sw1 != 0x90 or sw1 != 0x91:
                        msg = "?????? ??????? ? ?????"
                        return msg
                except NoCardException:
                    msg = "ADM0 getting error. Error code: " + str(hex(sw1)) 
+ str(hex(sw2))

        msg = "Ok"
        return msg


class appMainFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, -1, title, pos=(150,150), 
size=(640,400), style = wx.CAPTION | wx.MINIMIZE_BOX | wx.CLOSE_BOX | 
wx.SYSTEM_MENU)

        self.panel = wx.Panel(self)

        # select reader controls
        self.selectReaderTxt = wx.StaticText(self.panel, -1, "?????????? 
???????? reader: ", pos = (10, 12), size = (170, 21))
        self.readerChoice = wx.Choice(self.panel, 120, pos = (180, 10), size 
= (230,21), choices=['?? ??????'])
        self.readerChoice.Select( 0 )
        EVT_CHOICE( self, 120, self.selectReader)
        self.cardDescr = wx.TextCtrl(self.panel, -1, "????? ?? ?????????", 
pos = (415, 10), size = (205,21), style = wx.TE_READONLY )

        self.staticLine2 = wx.StaticLine( self.panel, 210, pos = (10, 40), 
size = (610, 2) )

        #Log
        self.logAreaTxt = wx.StaticText(self.panel, -1, "??????: ", pos = 
(10, 50), size = (105, 21))
        self.logArea = wx.TextCtrl( self.panel, 301, "", pos = (10, 72), 
size = (610, 260), style=wx.TE_MULTILINE | wx.TE_READONLY )
        self.saveLogButton = wx.Button( self.panel, -1, "?????? ??????? ? 
????", pos = (20, 345) )
        EVT_BUTTON( self, self.saveLogButton.GetId(), self.OnSaveLog )

        #Buttons
        self.resetButton = wx.Button( self.panel, -1, "?????", pos = (300, 
345) )
        self.startButton = wx.Button( self. panel, -1, "?????", pos = (380, 
345) )
        self.closeButton = wx.Button( self.panel, -1, "?????", pos = (460, 
345) )
        EVT_BUTTON( self, self.resetButton.GetId(), self.OnReset )
        EVT_BUTTON( self, self.startButton.GetId(), self.OnStart )
        EVT_BUTTON( self, self.closeButton.GetId(), self.OnClose )


        # Set properties
        self.SetTitle(title)

        self.Layout()

        #Smart card operations
        self.scOps = SmartCardOperations()

        self.START = False
        self.step = None
        self.cardEvent = threading.Event()

    def selectReader(self, event):
        self.selectedReader = event.GetString()
        self.cardDescr.SetValue( self.scOps.getATR(self.selectedReader) )

    def removeReaders( self, removedreaders ):
        for readerToRemove in removedreaders:
            self.readerChoice.Delete( self.readerChoice.FindString( str( 
readerToRemove ) ) )

    def addReaders( self, addedreaders ):
        for readerToAdd in addedreaders:
            self.readerChoice.Append( str ( readerToAdd ) )

    def removeCards( self, removedcards ):
        if self.readerChoice.GetSelection() != 0:
            self.cardDescr.SetValue("????? ?? ?????????.")
        else:
            self.cardDescr.SetValue("?? ?????? reader.")

    def addCards( self, cardsToAdd ):
        if self.readerChoice.GetSelection() != 0:
            self.cardDescr.SetValue( 
self.scOps.getATR(self.selectedReader) )
            if self.START == True:
                rpdb2.settrace()
                if self.step != None:
                    self.step.release()
                #self.cardEvent.set()

    def OnReset( self, event ):
        if self.step != None:
            self.step = None
        self.START = False
        self.logArea.AppendText("????? ????????. ??? ?????? ??????? 
?????\n")
        event.Skip()

    def OnClose( self, event ):
        sys.exit()
        event.Skip()

    def OnStart( self, event ):
        self.START = True
        self.step = threading.Semaphore(0)
        if self.step == 0:
            #start process
            #STAGE 1
            self.logArea.AppendText( "1. ?????????? ???????? ?????????????? 
????? ? reader\n" )
            iccid, plainIccid = self.stage1()

            if iccid == None:
                event.Skip()
                return None
            self.logArea.AppendText( "?????????? ?????? ?????????????? 
?????\n" )

            #STAGE 2
            self.logArea.AppendText( "2. ?????????? ???????? SAM ????? ? 
reader\n" )
            adm0 = self.stage2( plainIccid )
            if adm0 == None:
                event.Skip()
                return None
            self.logArea.AppendText( "?????????? ?????? SAM ?????\n" )

            #STAGE 3
            self.logArea.AppendText( "3. ?????????? ???????? ?????????????? 
????? ? reader\n" )
            result = self.stage3(iccid, adm0)
            if result == True:
                self.logArea.AppendText( "????? ??????? ??????????\n" )
            else:
                self.logArea.AppendText( "?????? ????????? ?????.\n" )

        else:
            self.logArea.AppendText( "??????? ??? ???????? ? ???????????? 
??????????????????. ??????? ????? ? ??????? ??????\n" )

        self.step = None
        self.START = False

    def stage1( self ):
        #wait SIM card insertion
        while self.step != 1:
            pass
        rpdb2.settrace()
###########################BLOCKING HERE##################################
        if not self.cardEvent.isSet():
            self.cardEvent.wait()
        self.cardEvent.clear()

        #check inserted card is a SIM card
        msg, atr = self.scOps.getATR( self.selectedReader )
        while atr == SAM_ATR:
            self.logArea.AppendText( "??????????? ????? ???????? SAM ??????. 
?????????? ???????? SIM ????? ? reader\n" )
           ########## Decrement semaphore  value##############
            self.step.acquire()
            msg, atr = self.scOps.getATR( self.selectedReader )
            if msg != "Ok":
                self.logArea.AppendText( "?????? ?????? ?????. ??????? ????? 
? ??????? ??????\n" )
                return None, None

        #read iccid of sim card
        msg, iccid, plainIccid = self.scOps.getICCID( self.selectedReader )
        if msg != "Ok":
            self.logArea.AppendText( "?????? ??????  ?????. ??????? ????? ? 
??????? ??????\n" )
            return None, None

        return iccid, plainIccid

    def stage2( self, iccid ):
        #wait SAM card insertion
        while self.step != 2:
            pass
        #while not self.cardEvent.isSet():
        #    self.cardEvent.wait()
        #self.cardEvent.clear()

        #check is it SAM card
        msg, atr = self.scOps.getATR( self.selectedReader )
        while atr != SAM_ATR:
            self.logArea.AppendText( "??????????? ????? ???????? ?? SAM 
??????. ?????????? ???????? SAM ????? ? reader\n" )
            ########## Decrement semaphore  value##############
            self.step.acquire()
            msg, atr = self.scOps.getATR( self.selectedReader )
            if msg != "Ok":
                self.logArea.AppendText( "?????? ?????? ?????. ??????? ????? 
? ??????? ??????\n" )
                return None

        #get ADM0 key
        msg, adm0 = self.scOps.getADM0( self.selectedReader, iccid )
        if msg != "Ok":
                self.logArea.AppendText( "??????  ?????? ? SAM ??????. 
??????? ????? ? ??????? ??????\n" )
                return None

        return adm0

    def stage3( self, old_iccid, adm0 ):
        #wait SIM card insertion
        while self.step != 3:
           pass
        #while not self.cardEvent.isSet():
        #    self.cardEvent.wait()

        #self.cardEvent.clear()


        #check ATR
        msg, atr = self.scOps.getATR( self.selectedReader )
        while atr == SAM_ATR:
            self.logArea.AppendText( "??????????? ????? ???????? ?? SAM 
??????. ?????????? ???????? SAM ????? ? reader\n" )
            ########## Decrement semaphore  value##############
            self.step.acquire()
            msg, atr = self.scOps.getATR( self.selectedReader )
            if msg != "Ok":
                return False

        #check iccid
        msg, new_iccid, plain_new_iccid = self.scOps.getICCID( 
self.selectedReader )

        if msg != "Ok":
            return False

        while old_iccid != new_iccid:
            if old_iccid != new_iccid:
                self.logArea.AppendText( "? reader ????????? ????? ? ICCID=" 
+ str(new_iccid) + ". ????????? ??????? ????? ? ICCID=" + str(old_iccid))

        msg = self.scOps.chgEfLnd(plain_new_iccid, adm0)
        if msg != "Ok":
            return False

        return True

    def OnSaveLog(self, event):
        dlg = wx.FileDialog(self, "Choose a file", ".", "", "*.*", wx.OPEN)
        try:
            if dlg.ShowModal() == wx.ID_OK:
                filename = dlg.GetPath()
                logfile = open(filename, 'w')
                logfile.write(self.logArea.GetValue())
                logfile.close()
        finally:
            dlg.Destroy()

    def showMessage( self, message, title):
        msgWin = wxMessageDialog ( None, message, title, wxOK )
        msgWin.ShowModal()
        msgWin.Destroy()


class ReadersObserver:
    def __init__ ( self, frame ):
        self.mainFrame = frame
    def update( self, observable, ( addedreaders, removedreaders ) ):
        self.mainFrame.removeReaders( removedreaders )
        self.mainFrame.addReaders( addedreaders )

class CardsObserver:
    def __init__( self, frame ):
        self.mainFrame = frame
    def update( self, observable, ( addedcards, removedcards ) ):
        self.mainFrame.removeCards( removedcards )
        self.mainFrame.addCards( addedcards )



class appChgLnd(wx.PySimpleApp):
    def OnInit(self):
        #create frame
        self.appFrame = appMainFrame(None, "SimUpdate")
        self.SetTopWindow( self.appFrame )

        #create observer class instances
        readersObserver = ReadersObserver( self.appFrame )
        cardsObserver = CardsObserver( self.appFrame )

        #subscribe to readers monitor and card monitor
        self.cardsMonitor = CardMonitor()
        self.cardsMonitor.addObserver( cardsObserver )
        self.readersMonitor = ReaderMonitor()
        self.readersMonitor.addObserver( readersObserver )

        #show frame
        self.appFrame.Show(True)
        return True

if __name__ == '__main__':
    try:
        app = appChgLnd(0)
        app.MainLoop()
    except:
        traceback.print_exc( file=open('errors.log', 'w'))




########################################## CARD 
OBSERVER###################################
from sys import exc_info
from threading import Thread, Event
from time import sleep

from smartcard.System import readers
from smartcard.Exceptions import CardRequestTimeoutException
from smartcard.Observer import Observer
from smartcard.Observer import Observable

from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest

# CardObserver interface
class CardObserver(Observer):
    """
    CardObserver is a base abstract class for objects that are to be 
notified
    upon smartcard reader insertion/removal.
    """
    def __init__(self):
        pass
    def update( self, observable, (addedcards, removedcards) ):
        """Called upon reader insertion/removal.

        observable:
        addedcards: list of added readers causing notification
        removedcards: list of removed readers causing notification
        """
        pass

class CardMonitor:
    """Class that monitors smart card insertion/removal.
    and notify observers

    """

    class __CardMonitorSingleton( Observable ):
        """The real smartcard monitor class.

        A single instance of this class is created
        by the public CardMonitor class.
        """
        def __init__(self):
            Observable.__init__(self)
            self.rmthread=None

        def addObserver(self, observer):
            """Add an observer.

            We only start the card monitoring thread when
            there are observers.
            """
            Observable.addObserver( self, observer )
            if self.countObservers()>0 and self.rmthread==None:
                self.rmthread = CardMonitoringThread( self )

        def deleteObserver(self, observer):
            """Remove an observer.

            We delete the CardMonitoringThread reference when there
            are no more observers.
            """
            Observable.deleteObserver( self, observer )
            if self.countObservers()==0:
                if self.rmthread!=None:
                    self.rmthread=None

    # the singleton
    instance = None

    def __init__(self):
        if not CardMonitor.instance:
            CardMonitor.instance = CardMonitor.__CardMonitorSingleton()

    def __getattr__(self, name):
        return getattr(self.instance, name)


class CardMonitoringThread:
    """Card insertion thread.
    This thread waits for card insertion.
    """

    class __CardMonitoringThreadSingleton( Thread ):
        """The real card monitoring thread class.

        A single instance of this class is created
        by the public CardMonitoringThread class.
        """
        def __init__(self, observable):
            Thread.__init__(self)
            self.observable=observable
            self.stopEvent = Event()
            self.stopEvent.clear()
            self.cards = []
            self.cardrequest = CardRequest( timeout=2 )
            self.setDaemon(True)

        # the actual monitoring thread
        def run(self):
            """Runs until stopEvent is notified, and notify
            observers of all card insertion/removal.
            """
            while self.stopEvent.isSet()!=1:
                try:
                    currentcards = self.cardrequest.waitforcardevent()

                    addedcards=[]
                    for card in currentcards:
                        if not self.cards.__contains__( card ):
                            addedcards.append( card )

                    removedcards=[]
                    for card in self.cards:
                        if not currentcards.__contains__( card ):
                            removedcards.append( card )

                    if addedcards!=[] or removedcards!=[]:
                        self.cards=currentcards
                        self.observable.setChanged()
                        self.observable.notifyObservers( (addedcards, 
removedcards) )

                except:
                    import sys
                    print sys.exc_info()[1]
                    print sys.exc_info()[2]
                    print sys.exc_info()[0]

        # stop the thread by signaling stopEvent
        def stop(self):
            self.stopEvent.set()

    # the singleton
    instance = None

    def __init__(self, observable):
        if not CardMonitoringThread.instance:
            CardMonitoringThread.instance = 
CardMonitoringThread.__CardMonitoringThreadSingleton( observable )
            CardMonitoringThread.instance.start()


    def __getattr__(self, name):
        return getattr(self.instance, name)

    def __del__(self):
        if CardMonitoringThread.instance!=None:
            CardMonitoringThread.instance.stop()
            CardMonitoringThread.instance = None


##################################### GENERAL 
OBSERVER##############################
Class support for "observer" pattern.

The observer class is the base class
for all smartcard package observers.

"""

from smartcard.Synchronization import *

class Observer:
  def update(observable, arg):
    '''Called when the observed object is
    modified. You call an Observable object's
    notifyObservers method to notify all the
    object's observers of the change.'''
    pass

class Observable(Synchronization):
  def __init__(self):
    self.obs = []
    self.changed = 0
    Synchronization.__init__(self)

  def addObserver(self, observer):
    if observer not in self.obs:
      self.obs.append(observer)

  def deleteObserver(self, observer):
    self.obs.remove(observer)

  def notifyObservers(self, arg = None):
    '''If 'changed' indicates that this object
    has changed, notify all its observers, then
    call clearChanged(). Each observer has its
    update() called with two arguments: this
    observable object and the generic 'arg'.'''

    self.mutex.acquire()
    try:
      if not self.changed: return
      # Make a local copy in case of synchronous
      # additions of observers:
      localArray = self.obs[:]
      self.clearChanged()
    finally:
      self.mutex.release()
    # Updating is not required to be synchronized:
    for observer in localArray:
      observer.update(self, arg)

  def deleteObservers(self): self.obs = []
  def setChanged(self): self.changed = 1
  def clearChanged(self): self.changed = 0
  def hasChanged(self): return self.changed
  def countObservers(self): return len(self.obs)

synchronize(Observable,
  "addObserver deleteObserver deleteObservers " +
  "setChanged clearChanged hasChanged " +
  "countObservers")
#:~


############################ SYNC######################

Simple emulation of Java's 'synchronized'
keyword, from Peter Norvig.
"""

from threading import RLock

def synchronized(method):
  def f(*args):
    self = args[0]
    self.mutex.acquire();
    # print method.__name__, 'acquired'
    try:
      return apply(method, args)
    finally:
      self.mutex.release();
      # print method.__name__, 'released'
  return f

def synchronize(klass, names=None):
  """Synchronize methods in the given class.
  Only synchronize the methods whose names are
  given, or all methods if names=None."""
  if type(names)==type(''): names = names.split()
  for (name, val) in klass.__dict__.items():
    if callable(val) and name != '__init__' and \
      (names == None or name in names):
        # print "synchronizing", name
        klass.__dict__[name] = synchronized(val)

# You can create your own self.mutex, or inherit
# from this class:
class Synchronization:
  def __init__(self):
    self.mutex = RLock()
#:~ 





More information about the Python-list mailing list