Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Misleading documentation for ctypes.PYFUNCTYPE #114150

Copy link
Copy link
@arrmansa

Description

@arrmansa
Issue body actions

Main Issue

documentation for ctypes.PYFUNCTYPE in cytpes is misleading

The returned function prototype creates functions that use the Python calling convention. The function will not release the GIL during the call.

Proposal

I think it should be updated to something else, indicating that the GIL is acquired and used as normal, rather than held until the call is complete -

The returned function prototype creates functions that use the Python calling convention. The function will acquire the GIL and use it like normal python code during the call.

What I was trying

I was trying to create a function that holds the python GIL for x seconds without releasing it. I wanted to use this to test some functions that should release the GIL and still allow the GIL to be acquired by another function.
the documentation for ctypes.PYFUNCTYPE mislead me into thinking wrapping a time.sleep call with this would hold the GIL- (The function will not release the GIL during the call)

How I tested it

1. create an example.c file

// example.c
#include <stdio.h>
#include <Python.h>

void run_in_c(int value, void (*callback)(int)) {
    printf("C function called with %d\n", value);
    callback(value);
}

// compile with
// export C_INCLUDE_PATH="/usr/local/Cellar//python@3.11/3.11.7/Frameworks/Python.framework/Versions/3.11/include/python3.11"
// gcc -shared -o example.so -fPIC example.c

2. compile to create example.so

export C_INCLUDE_PATH="/usr/local/Cellar//python@3.11/3.11.7/Frameworks/Python.framework/Versions/3.11/include/python3.11"
gcc -shared -o example.so -fPIC example.c

3. run a python file to see if we created a function that does not release the GIL

import ctypes
from concurrent.futures import ThreadPoolExecutor
import time

example_lib = ctypes.CDLL('example.so')

def newfn(x):
    time.sleep(x)
    print("ran in python", x)

should_block_gil = ctypes.PYFUNCTYPE(None, ctypes.c_int)(newfn)

def blocking_sleep(x):
    example_lib.run_in_c(x, should_block_gil)

start = time.perf_counter()
results = ThreadPoolExecutor(2).map(blocking_sleep, [1]*2)
blocking_sleep(1)
print(list(results))
print(time.perf_counter() - start)

The output was

C function called with 1
C function called with 1
C function called with 1
ran in python 1
ran in python 1
ran in python 1
[None, None]
1.002278681

clearly indicating that the GIL was released by time.sleep

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.