prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  atexit module can't handle multiple instances
  The `atexit` module uses a dictionary to keep track of the routines to call.  This means that no routines can be registered more than once, for example with different arguments.
  
  Additionally, this means that `pwnlib.atexit` does not guarantee order.
  
  Per the [Python documentation](https://docs.python.org/2/library/atexit.html#module-atexit) for `atexit`:
  
  _atexit runs these functions in the reverse order in which they were registered; if you register A, B, and C, at interpreter termination time they will be run in the order C, B, A._
  
  However, multiple registration of routines breaks `unregister` in its current incarnation.  The suggested remedy for this is to return a unique ID for each `register` call that is passed to `unregister`, rather than passing in the function to `unregister`.
  
  
  </issue>
  <code>
  [start of pwnlib/atexit.py]
  1 """
  2 Replacement for the Python standard library's atexit.py.
  3 
  4 Whereas the standard :mod:`atexit` module only defines :func:`atexit.register`,
  5 this replacement module also defines :func:`unregister`.
  6 
  7 This module also fixes a the issue that exceptions raised by an exit handler is
  8 printed twice when the standard :mod:`atexit` is used.
  9 """
  10 
  11 import sys, traceback
  12 
  13 __all__ = ['register', 'unregister']
  14 
  15 _handlers = {}
  16 
  17 def register(func, *args, **kwargs):
  18     """register(func, *args, **kwargs)
  19 
  20     Registers a function to be called when an unhandled exception occurs.  The
  21     function will be called with positional arguments `args` and keyword
  22     arguments `kwargs`, i.e. ``func(*args, **kwargs)``.
  23 
  24     If `func` is already registered then `args` and `kwargs` will be updated.
  25 
  26     This function can be used as a decorator::
  27 
  28       def f():
  29         ...
  30       atexit.register(f)
  31 
  32     is equivalent to this::
  33 
  34       @atexit.register
  35       def f():
  36         ...
  37 
  38     """
  39     _handlers[func] = (args, kwargs)
  40     return func
  41 
  42 def unregister(func):
  43     """unregister(func)
  44 
  45     Remove `func` from the collection of registered functions.  If `func` isn't
  46     registered this is a no-op.
  47     """
  48     if func in _handlers:
  49         del _handlers[func]
  50 
  51 def _run_handlers():
  52     """_run_handlers()
  53 
  54     Run registered exit handlers.  The order is arbitrary.
  55 
  56     If a handler raises an exception, it will be printed but nothing else
  57     happens, i.e. other handlers will be run and `sys.excepthook` will not be
  58     called for that reason.
  59     """
  60     for func, (args, kwargs) in _handlers.items():
  61         try:
  62             func(*args, **kwargs)
  63         except SystemExit:
  64             pass
  65         except:
  66             # extract the current exception and rewind the traceback to where it
  67             # originated
  68             typ, val, tb = sys.exc_info()
  69             traceback.print_exception(typ, val, tb.tb_next)
  70 
  71 # if there's already an exitfunc registered be sure to run that too
  72 if hasattr(sys, "exitfunc"):
  73     register(sys.exitfunc)
  74 
  75 sys.exitfunc = _run_handlers
  76
  [end of pwnlib/atexit.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/pwnlib/atexit.py b/pwnlib/atexit.py
  --- a/pwnlib/atexit.py
  +++ b/pwnlib/atexit.py
  @@ -8,58 +8,76 @@
   printed twice when the standard :mod:`atexit` is used.
   """
   
  -import sys, traceback
  +import sys, traceback, threading
  +from .context import context
   
   __all__ = ['register', 'unregister']
   
  +_lock = threading.Lock()
  +_ident = 0
   _handlers = {}
   
   def register(func, *args, **kwargs):
       """register(func, *args, **kwargs)
   
  -    Registers a function to be called when an unhandled exception occurs.  The
  -    function will be called with positional arguments `args` and keyword
  -    arguments `kwargs`, i.e. ``func(*args, **kwargs)``.
  +    Registers a function to be called on program termination.  The function will
  +    be called with positional arguments `args` and keyword arguments `kwargs`,
  +    i.e. ``func(*args, **kwargs)``.  The current `context` is recorded and will
  +    be the one used when the handler is run.
   
  -    If `func` is already registered then `args` and `kwargs` will be updated.
  +    E.g. to suppress logging output from an exit-handler one could write::
   
  -    This function can be used as a decorator::
  +      with context.local(log_level = 'error'):
  +        atexit.register(handler)
   
  -      def f():
  -        ...
  -      atexit.register(f)
  +    An identifier is returned which can be used to unregister the exit-handler.
   
  -    is equivalent to this::
  +    This function can be used as a decorator::
   
         @atexit.register
  -      def f():
  +      def handler():
           ...
   
  -    """
  -    _handlers[func] = (args, kwargs)
  -    return func
  +    Notice however that this will bind ``handler`` to the identifier and not the
  +    actual exit-handler.  The exit-handler can then be unregistered with::
  +
  +      atexit.unregister(handler)
   
  -def unregister(func):
  -    """unregister(func)
  +    This function is thread safe.
   
  -    Remove `func` from the collection of registered functions.  If `func` isn't
  -    registered this is a no-op.
       """
  -    if func in _handlers:
  -        del _handlers[func]
  +    global _ident
  +    with _lock:
  +        ident = _ident
  +        _ident += 1
  +    _handlers[ident] = (func, args, kwargs, vars(context))
  +    return ident
  +
  +def unregister(ident):
  +    """unregister(ident)
  +
  +    Remove the exit-handler identified by `ident` from the list of registered
  +    handlers.  If `ident` isn't registered this is a no-op.
  +    """
  +    if ident in _handlers:
  +        del _handlers[ident]
   
   def _run_handlers():
       """_run_handlers()
   
  -    Run registered exit handlers.  The order is arbitrary.
  +    Run registered exit-handlers.  They run in the reverse order of which they
  +    were registered.
   
       If a handler raises an exception, it will be printed but nothing else
       happens, i.e. other handlers will be run and `sys.excepthook` will not be
       called for that reason.
       """
  -    for func, (args, kwargs) in _handlers.items():
  +    context.clear()
  +    for _ident, (func, args, kwargs, ctx) in \
  +        sorted(_handlers.items(), reverse = True):
           try:
  -            func(*args, **kwargs)
  +            with context.local(**ctx):
  +                func(*args, **kwargs)
           except SystemExit:
               pass
           except:
  
verification_info: {"golden_diff": "diff --git a/pwnlib/atexit.py b/pwnlib/atexit.py\n--- a/pwnlib/atexit.py\n+++ b/pwnlib/atexit.py\n@@ -8,58 +8,76 @@\n printed twice when the standard :mod:`atexit` is used.\n \"\"\"\n \n-import sys, traceback\n+import sys, traceback, threading\n+from .context import context\n \n __all__ = ['register', 'unregister']\n \n+_lock = threading.Lock()\n+_ident = 0\n _handlers = {}\n \n def register(func, *args, **kwargs):\n     \"\"\"register(func, *args, **kwargs)\n \n-    Registers a function to be called when an unhandled exception occurs.  The\n-    function will be called with positional arguments `args` and keyword\n-    arguments `kwargs`, i.e. ``func(*args, **kwargs)``.\n+    Registers a function to be called on program termination.  The function will\n+    be called with positional arguments `args` and keyword arguments `kwargs`,\n+    i.e. ``func(*args, **kwargs)``.  The current `context` is recorded and will\n+    be the one used when the handler is run.\n \n-    If `func` is already registered then `args` and `kwargs` will be updated.\n+    E.g. to suppress logging output from an exit-handler one could write::\n \n-    This function can be used as a decorator::\n+      with context.local(log_level = 'error'):\n+        atexit.register(handler)\n \n-      def f():\n-        ...\n-      atexit.register(f)\n+    An identifier is returned which can be used to unregister the exit-handler.\n \n-    is equivalent to this::\n+    This function can be used as a decorator::\n \n       @atexit.register\n-      def f():\n+      def handler():\n         ...\n \n-    \"\"\"\n-    _handlers[func] = (args, kwargs)\n-    return func\n+    Notice however that this will bind ``handler`` to the identifier and not the\n+    actual exit-handler.  The exit-handler can then be unregistered with::\n+\n+      atexit.unregister(handler)\n \n-def unregister(func):\n-    \"\"\"unregister(func)\n+    This function is thread safe.\n \n-    Remove `func` from the collection of registered functions.  If `func` isn't\n-    registered this is a no-op.\n     \"\"\"\n-    if func in _handlers:\n-        del _handlers[func]\n+    global _ident\n+    with _lock:\n+        ident = _ident\n+        _ident += 1\n+    _handlers[ident] = (func, args, kwargs, vars(context))\n+    return ident\n+\n+def unregister(ident):\n+    \"\"\"unregister(ident)\n+\n+    Remove the exit-handler identified by `ident` from the list of registered\n+    handlers.  If `ident` isn't registered this is a no-op.\n+    \"\"\"\n+    if ident in _handlers:\n+        del _handlers[ident]\n \n def _run_handlers():\n     \"\"\"_run_handlers()\n \n-    Run registered exit handlers.  The order is arbitrary.\n+    Run registered exit-handlers.  They run in the reverse order of which they\n+    were registered.\n \n     If a handler raises an exception, it will be printed but nothing else\n     happens, i.e. other handlers will be run and `sys.excepthook` will not be\n     called for that reason.\n     \"\"\"\n-    for func, (args, kwargs) in _handlers.items():\n+    context.clear()\n+    for _ident, (func, args, kwargs, ctx) in \\\n+        sorted(_handlers.items(), reverse = True):\n         try:\n-            func(*args, **kwargs)\n+            with context.local(**ctx):\n+                func(*args, **kwargs)\n         except SystemExit:\n             pass\n         except:\n", "issue": "atexit module can't handle multiple instances\nThe `atexit` module uses a dictionary to keep track of the routines to call.  This means that no routines can be registered more than once, for example with different arguments.\n\nAdditionally, this means that `pwnlib.atexit` does not guarantee order.\n\nPer the [Python documentation](https://docs.python.org/2/library/atexit.html#module-atexit) for `atexit`:\n\n_atexit runs these functions in the reverse order in which they were registered; if you register A, B, and C, at interpreter termination time they will be run in the order C, B, A._\n\nHowever, multiple registration of routines breaks `unregister` in its current incarnation.  The suggested remedy for this is to return a unique ID for each `register` call that is passed to `unregister`, rather than passing in the function to `unregister`.\n\n", "before_files": [{"content": "\"\"\"\nReplacement for the Python standard library's atexit.py.\n\nWhereas the standard :mod:`atexit` module only defines :func:`atexit.register`,\nthis replacement module also defines :func:`unregister`.\n\nThis module also fixes a the issue that exceptions raised by an exit handler is\nprinted twice when the standard :mod:`atexit` is used.\n\"\"\"\n\nimport sys, traceback\n\n__all__ = ['register', 'unregister']\n\n_handlers = {}\n\ndef register(func, *args, **kwargs):\n    \"\"\"register(func, *args, **kwargs)\n\n    Registers a function to be called when an unhandled exception occurs.  The\n    function will be called with positional arguments `args` and keyword\n    arguments `kwargs`, i.e. ``func(*args, **kwargs)``.\n\n    If `func` is already registered then `args` and `kwargs` will be updated.\n\n    This function can be used as a decorator::\n\n      def f():\n        ...\n      atexit.register(f)\n\n    is equivalent to this::\n\n      @atexit.register\n      def f():\n        ...\n\n    \"\"\"\n    _handlers[func] = (args, kwargs)\n    return func\n\ndef unregister(func):\n    \"\"\"unregister(func)\n\n    Remove `func` from the collection of registered functions.  If `func` isn't\n    registered this is a no-op.\n    \"\"\"\n    if func in _handlers:\n        del _handlers[func]\n\ndef _run_handlers():\n    \"\"\"_run_handlers()\n\n    Run registered exit handlers.  The order is arbitrary.\n\n    If a handler raises an exception, it will be printed but nothing else\n    happens, i.e. other handlers will be run and `sys.excepthook` will not be\n    called for that reason.\n    \"\"\"\n    for func, (args, kwargs) in _handlers.items():\n        try:\n            func(*args, **kwargs)\n        except SystemExit:\n            pass\n        except:\n            # extract the current exception and rewind the traceback to where it\n            # originated\n            typ, val, tb = sys.exc_info()\n            traceback.print_exception(typ, val, tb.tb_next)\n\n# if there's already an exitfunc registered be sure to run that too\nif hasattr(sys, \"exitfunc\"):\n    register(sys.exitfunc)\n\nsys.exitfunc = _run_handlers\n", "path": "pwnlib/atexit.py"}]}