-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PyFile support #11
Comments
First of all, note that That said, look at https://github.com/Stewori/JyNI/blob/master/JyNI-C/include/JyNI_JNI.h#L508 and https://github.com/Stewori/JyNI/blob/master/JyNI-C/src/JyNI_JNI.c#L449 and https://github.com/Stewori/JyNI/blob/master/JyNI-C/src/JyNI_JNI.c#L1100. At these three spots you must declare functions in Jython for C-access. https://github.com/Stewori/JyNI/blob/master/JyNI-C/include/JNI_util.h declares a bunch of magic and macros to simplify JNI-based declarations. Originally it was even more painful. See the macros https://github.com/Stewori/JyNI/blob/master/JyNI-C/include/JNI_util.h#L133 and below. These are meant for public access: Yes, I have to document these (please help with that if you can!) Look at https://github.com/Stewori/JyNI/blob/master/JyNI-C/src/JyNI_JNI.c for plenty usage examples. Feel free to ask further questions if you struggle with using these macros. Note that |
In http://www.kfu.com/%7Ensayer/Java/jni-filedesc.html we can see that |
Functions that don't access internals of the |
Ok, I have followed your advice. I have first exported the filedescriptor, which was already accessible in the Jython API (through the usual reflection hack in This was much easier than unwrapping the nested objects through the C API for me, but this is obviously only a hack to see how far I can get. I then added the necessary method declarations as you suggested: I can import matplotlib.pyplot now (pylab still crashes): whilo@c51c277#diff-753c9fd4810cb43fc681a2eae65157cc I can create a plot object, but after the tkinter window pops up the process immediately crashes. christian@lacan ~/D/JyNI> java -cp jython.jar:build/JyNI.jar org.python.util.jython
Jython 2.7.1rc3 (, Jun 19 2017, 12:45:06)
[OpenJDK 64-Bit Server VM (Oracle Corporation)] on java1.8.0_131
Type "help", "copyright", "credits" or "license" for more information.
>>> import setup_path
>>> import matplotlib.pyplot as plt
>>> plt.plot([1,2,3])
[<matplotlib.lines.Line2D object at 0x2a3>]
>>> plt.show()
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f93d1a0bdc8, pid=16675, tid=0x00007f93fa375700
#
# JRE version: OpenJDK Runtime Environment (8.0_131-b11) (build 1.8.0_131-8u131-b11-0ubuntu1.17.04.1-b11)
# Java VM: OpenJDK 64-Bit Server VM (25.131-b11 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C [multiarray.x86_64-linux-gnu.so+0x5adc8]
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/christian/Development/JyNI/hs_err_pid16675.log
Compiled method (c1) 48634 4793 1 JyNI.gc.DefaultTraversableGCHead::setLinks (6 bytes)
total in heap [0x00007f93e17affd0,0x00007f93e17b0288] = 696
relocation [0x00007f93e17b00f8,0x00007f93e17b0120] = 40
main code [0x00007f93e17b0120,0x00007f93e17b01c0] = 160
stub code [0x00007f93e17b01c0,0x00007f93e17b0250] = 144
oops [0x00007f93e17b0250,0x00007f93e17b0258] = 8
scopes data [0x00007f93e17b0258,0x00007f93e17b0260] = 8
scopes pcs [0x00007f93e17b0260,0x00007f93e17b0280] = 32
dependencies [0x00007f93e17b0280,0x00007f93e17b0288] = 8
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
fish: 'java -cp jython.jar:build/JyNI.…' terminated by signal SIGABRT (Abbruch) I can read the error log, but I guess I should study the dumps? It points to multiarray, so I guess it is not related to further PyFile methods. I would tackle them, but first I would like to get matplotlib basically running. What are your suggestions? |
Is the issue reproducible? Can you isolate the Python code in matplotlib that provokes the crash? |
Issue is here now: #12 |
Whilo, could you build a PR from what you achieved so far? That would make it easier for others (including myself) to reproduce the subsequent issue you describe. Please adjust your approach such that it works without modifications in Jython. IMO this would be not too complicated (one additional native field access). On the other hand, having in mind that Jython is currently in late RC-phase for 2.7.1 release, such a change would only make it into Jython 2.7.2 and I wouldn't make a guess when this release will happen (hopefully the huge delay of 2.7.1 was an exception, but let's better not rely on that). |
Sure, I can do that. The current approach is a hack to get something working and start from there. I don't think I need a patched Jython version. |
Hey whilo. Just posting a polite reminder to file a PR for your work on PyFile. It would be a pity to loose this, even if it's just a starting point so far... |
Thanks for the reminder, it is high on my todo list. :) |
So, my work on porting JyNI to Windows is almost done. This means, it is a good time for a next release. Do you think we can get some PyFile support into JyNI alpha 5? |
Thanks for insisting. I will sit down and work on it this evening. Will you be online on IRC? |
I can go online on IRC later. Note that it's not due exactly today. I'd like to make the release somewhat end of the week or next weekend. Also, it's not totally crucial to get PyFile into this release, but it would be nice. |
So, I am observing IRC log frequently, but I cannot guarantee that I can be online at a particular time. Ithink it would be best to resolve questions here in an async manner. |
Ok, I have been there late in the evening, but I guess it was too late :). I have tried to do the JVM PyFile API calls in the C context, but somehow printing (printf) does not work anymore. I am not sure why. |
|
Right, the C routine |
Maybe there is some test code in CPython. Otherwise we should maybe write our own test(s). DemoExtension is intended to serve as a collection for native test code. |
Ok, deleting the fontcache of matplotlib did the trick for now. But now I need to cast and access the FileIO object and I have no clue how to do that with JNI. I will try to figure it out, but having a general chat medium with offline capability, code formatting and mail notifications would really be helpful for this, especially to have some period of time where I can just ask you dumb questions. From the open-source projects I run and support I can really recommend setting up gitter. It is open-source, is integrated with github and takes maybe five minutes to setup. |
Maybe you can add PyFile.fd as a static method to |
FILE *
PyFile_AsFile(PyObject *f)
{
printf("Accessing file.\n");
env(-1);
if (f == NULL)
puts("PyFile_AsFile with NULL-pointer");
jobject f2 = JyNI_JythonPyObject_FromPyObject(f);
//(*env)->CallVoidMethod(env, ((JyObject*) f)->jy, pyFileWrite, (*env)->NewStringUTF(env, s));
jobject fileno = (*env)->CallObjectMethod(env, f2, pyFile_fileno);
printf("fileno: %i \n", fileno);
jobject fd_pyint = (*env)->CallObjectMethod(env, fileno, FileIO___int__);
jint fd_int = (*env)->CallObjectMethod(env, fd_pyint, pyInt_getValue);
printf("fd_int: %i \n", fd_int); // prints 0 ?!?
jint fd = (*env)->CallObjectMethod(env, f2, pyFile_fd);
printf("FD: %i \n", fd);
// TODO get mode from PyFile
return fdopen(fd, "r");
//todo: JNI Exception handling
} |
The fd_int printf line prints 0 and not the correct fd value. I guess that casting happens implicitly and if I try to call a non-existing method I get an exception from the JVM. |
So I ignored the casting issue, but the result makes no sense so far to me. I guess PyInteger is 0 by default due to JVM Integer being 0 by default, but I am at least getting a proper instance of it, which is weird. If I had done something wrong on the way to access it, it should have thrown or caused a segmentation fault. |
I have implemented the same path to fd as in |
If my current approach in C is actually worse in your opinion than adding a static method to JyNI (which is also somewhat odd by providing an external method for PyFile), then I will take that way. I thought it would be right to do it from C, without implementing custom helpers. |
should rather be
That should fix it.
Putting a sequence of Java calls to Java side is faster AFAIK, because it reduces calls from C into JVM which are JNI's slowest facet. That said, there is plenty of such stuff in JyNI. I guess I became a little painless about this. We can maybe add a proper method to Jython, but until that finds its way into a release, an external implementation in JyNI is a good migration path. |
I've started working on finishing implementing the PyFile API. It's on a separate branch/fork and I hope to have decent tests for the API before merging it with master. But if a working PyFile API is needed for anything then I can submit a pull request earlier. |
Question:I am unsure as to what to do about the memory management functions in PyFile, I feel like there will be some details about JyNI GC that will come into play here. The functions I am most unsure about are: PyFile_DecUseCount, PyFile_IncUseCount, tp_dealloc and tp_weaklistoffset. There are generic object functions for tp_alloc and tp_free, I haven't tested them yet so they may not work as they may also have quirks. General Progress Report:My current progress is on my Implementing-PyFile branch. Before submitting a pull request I will fix the git history and clean things up(I'm not used to memory management, variables aren't always declared at the start of blocks, etc). I just thought it was worth having the progress somewhere other than just my local eclipse workspace. Most of PyFile is done and passes tests (33/46). Other than the memory management things in the question, the remaining functions that don't have tests that they pass are: Tests: |
Re UseCount: It looks like in Jython the role of the handle is played by a |
Okay, I took a closer look.
Regarding the error case
I suggest to write a new subclass of
Did you already implement Hope this helps! I admit that makes PyFile implementation a bit more complicated than I originally expected. |
Maybe it would be cleaner to implement |
@CalumFreeman I think the effort of implementing With that done I suggest to shift focus to iterator support as it will have much higher impact. |
Ok, I've set CPython:
Jython:
This would be best fixed in jython although it's probably only noticed in JyNI/C extensions and we already have a workaround for the place it is most important. I don't think it's worth spending time on at this point, iterator support is more important. |
Regarding fileno please also see http://bugs.jython.org/issue2320. |
So, the situation seems to be as follows: |
Maybe you could commit your work to your own JyNI fork. That would be the preparation for a PR anyway. That would allow for an informal review. |
There are some branches on my own fork that sort of show what I've been doing. I've split the testing out into it's own branch to avoid conflicts when building tests for iterators and pyfile. PyFile has two branches, a messy one and a cleaned up one. The cleaned up one is (obviously) cleaner and they both pass the same tests so I think it is better. (There's also a branch for iterators, I've fixed the numpy.random.randint() bug but not much else. I want to do a lot more on that branch) |
Sorry, I somehow forgot to look for branches :) |
I'm tidying up PyFile so that it's ready for a PR and I have a few questions: In file_new I assume that I also need to deal with the args/kwds in file_init, would I'm still not entirely sure what to do for fileno, at the moment it just delegates to jython in the standard |
I think you have to do it like in SequenceIterator or in PySet. Creating a native object by converting it from the Java object is only supported for types that have an init function in JySync.c IIRC. Actually I would like to streamline this kind of creation and it might be that I once improved this in
Jython functions have a different call convention than CPython functions. While in CPython a tuple is passed for args and a dict for kw, in Jython it is only one tuple containing all args, plus optionally a string array assigning kw-interpretation to the trailng n args with n being the length of the string array (in Python 3 fastcall is an newer call convention that might work similar). Regarding |
Ok, I've updated filenoFor file_fileno, it could be implemented like this:
This would behave identically but still allow us to have whatever implementation is best But... Memory leak?I am slightly concerned that the current version of Because of all this the extensions won't clean up the Basically, I think the current implementation will have a memory leak. The only way I can think of to solve this would be to store the file pointer and implement Staying in sync?I'm also a little worried about keeping the |
The memory leak concern is exactly why I suggested to have only a single file pointer FILE*, tracked in Regarding sync, that requires more investigation. Already to assess whether it is an issue at all. Doing something meaningful on this front is not feasible in your remaining project time. Let's just say, for now concurrent file access via native C-API and Java-side Jython API is not supported or at least not tested. I think most C-extension would do the whole file access in C or in Python and not really mix it. As with the access counter we can revisit this if it actually causes problems. Injecting a custom FileIO backend (that keeps track of sync) into Jython could solve this ultimately if required. |
Yes, I thought that was one of the reasons you suggested tracking it, I didn't know it could affect fileno though. Without trying to sync things, the remaining things to do in PyFile are: tp_init is causing some trouble, probably because I'm not sure the test is right as I don't know how to set up the args/kwargs so they will parse correctly. I think this simple implementation should work:
But I don't really know for sure. I made a bit of an attempt at using the CPython implementation and using The simple implementation doesn't seem to cause any problems so I think it does no harm, so PyFile could be pulled without any problems, but I don't know if tp_init/tp_new actually work to create a valid file from C. (tp_new does create an object with type file, but that's all I know it does for sure). |
I should also note I have now added code to include |
I have explored supporting matplotlib font loading, which require PyFile support.
I have commented in
Which is called and immediately SIG_ABORTS. I get a dump file from the JVM:
Just returning
NULL
is not sufficient as a quick hack and I guess that I need to wrap a Jython class for PyFile instead of accessing the pointer directly. You said it would be easy to fix, but in the comment you say:I had some frustrations with filesystem APIs lately for my kv-store implementation, so I would also be careful with double access. What are your suggestions to proceed? Also do you have some chat channel? This might be easier to get started.
The text was updated successfully, but these errors were encountered: