or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/pyfuse3@3.4.x

docs

index.md
tile.json

tessl/pypi-pyfuse3

tessl install tessl/pypi-pyfuse3@3.4.0

Python 3 bindings for libfuse 3 with async I/O support

thread-safety.mddocs/guides/

Thread Safety Guide

Guide to thread safety, async operations, and cross-thread communication in pyfuse3.

Core Principles

  1. Operations are async: All handlers run in async context
  2. Use async primitives: Use trio.Lock or asyncio.Lock, not threading.Lock
  3. Cross-thread calls: Use trio.from_thread for calls from other threads
  4. Signal handlers: Must use trio.from_thread to call pyfuse3 functions

Async Synchronization

Using Locks

import trio

class ThreadSafeFS(pyfuse3.Operations):
    def __init__(self):
        super().__init__()
        self.inode_locks = {}  # Per-inode locks
        self.global_lock = trio.Lock()
    
    async def write(self, fh, offset, buf):
        """Write with per-inode locking."""
        inode = self.open_files[fh]
        
        # Get or create lock for this inode
        if inode not in self.inode_locks:
            async with self.global_lock:
                if inode not in self.inode_locks:
                    self.inode_locks[inode] = trio.Lock()
        
        # Perform write under lock
        async with self.inode_locks[inode]:
            data = self.inodes[inode]['data']
            # ... write logic ...
            self.inodes[inode]['data'] = new_data
        
        return len(buf)

Signal Handlers

Correct Pattern (Trio)

import trio
import trio.from_thread
import pyfuse3
import signal

async def run_filesystem():
    fs = MyFS()
    
    def signal_handler(signum, frame):
        """Signal handler - runs in different thread."""
        logger.info(f"Received signal {signum}")
        # CORRECT: Use trio.from_thread
        trio.from_thread.run_sync(
            pyfuse3.terminate,
            trio_token=pyfuse3.trio_token
        )
    
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    
    pyfuse3.init(fs, '/mnt/myfs')
    await pyfuse3.main()

Correct Pattern (Asyncio)

import asyncio
import pyfuse3
import signal

async def run_filesystem():
    fs = MyFS()
    
    def signal_handler(signum, frame):
        """Signal handler - runs in different thread."""
        logger.info(f"Received signal {signum}")
        # CORRECT: Use call_soon_threadsafe
        loop = asyncio.get_event_loop()
        loop.call_soon_threadsafe(pyfuse3.terminate)
    
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    
    pyfuse3.init(fs, '/mnt/myfs')
    await pyfuse3.main()

Incorrect Pattern

def signal_handler(signum, frame):
    # WRONG - Direct call from signal handler
    pyfuse3.terminate()  # May deadlock or crash!

Common Mistakes

Mistake 1: Using Threading Locks

import threading

# WRONG
class BadFS(pyfuse3.Operations):
    def __init__(self):
        self.lock = threading.Lock()  # Don't use threading locks!
    
    async def write(self, fh, offset, buf):
        with self.lock:  # This will block the async task!
            # ...

# CORRECT
import trio

class GoodFS(pyfuse3.Operations):
    def __init__(self):
        self.lock = trio.Lock()  # Use async lock
    
    async def write(self, fh, offset, buf):
        async with self.lock:  # Async context manager
            # ...

Mistake 2: Blocking Operations

# WRONG
async def read(self, fh, offset, size):
    import time
    time.sleep(1)  # Blocks entire worker task!
    return self.data[offset:offset + size]

# CORRECT
async def read(self, fh, offset, size):
    await trio.sleep(1)  # Yields to other tasks
    return self.data[offset:offset + size]

See Also

  • Error Handling Guide
  • Performance Tuning