The discussion about direct and indirect dependencies is coming up again on the FreeBSD mailinglists. Seems I should make some blog post about it, maybe it makes this topic more findable than my postings in the mailinglists.
Some definitions:
- A direct dependency from A to B is when program/port A uses symbols from library/port B.
- An indirect dependency from A to C is when program/port A uses symbols from library/port B but no symbols from library/port C, and library/port B uses symbols from library/port C.
- An explicit dependency from A to C is when it is a direct or indirect dependency A to C, and when the compiler-time-linker added an explicit reference to C to the program/lib of A.
Ideally we have no indirect dependencies in the explicit dependencies, only direct dependencies. Unfortunately in reality we also have indirect dependencies there. This has at least two causes:
- libtool (at least 1.x) does not (or was not) come with a hint on FreeBSD, which tells that the run-time-linker is recursively resolving dependencies.
- Some pkg-config setups list indirect dependencies as explicit dependencies (IIRC it depends if Requires.private and/or Libs.private is used in the .pc file or not; if it is used, there should be no indirect dependency appear from this software, but I am not 100% sure about this).
Three years ago I wrote /usr/ports/Tools/scripts/explicit_lib_depends.sh, it looks at the files of a given port (it needs to be installed), and prints out explicit dependencies. Because of the indirect dependencies which could be listed there, this list is not a list of ports which are real dependencies from a source code point of view, but it reflects the link-time reality. If a port C shows up there, the port which is checked needs to be rebuild in case the ABI of library/port C changes.
GD Star Rating
loading…
GD Star Rating
loading…
After all the big-impact commits (Gnome/gettext/KDE/X11/…) have settled now, I took the time to update audio/lame (I identified more than 100 ports with an (implicit) dependency on lame, 45 of them needed a portrevision bump; if I forgot/overlooked some, bump the revision yourself or notify me please). That is the first update of my ports where miwi@ did not beat me in committing an update since a year (he has implicit approval to do anything he wants with my ports).
I can be happy that he is/was this fast (and that we have such a productive and efficient committer), or I can be sad that I do not have the time anymore to be faster than I am with such things… or both. Hmmm… I think I will go the happy way.
GD Star Rating
loading…
GD Star Rating
loading…
I have an old system (only the hardware, it runs –current) which reboots itself from time to time (mostly during the daily periodic(8) run, but also during a lot of compiling (portupgrade)). There is no obvious reason (no panic) why it is doing this. It could be that there is some hardware defect, or something else. It is not important enough to get a high enough priority that I try hard to analyze the problem with this machine. The annoying part is, that sometimes after a restart apache does not start. So if this happens, the solution is to login and start the webserver. If the webserver would start each time, nearly nobody would detect the reboot (root gets an EMail on each reboot via an @reboot crontab entry).
My pragmatic solution (for services started via a good rc.d script which has a working status command) is a crontab entry which checks periodically if it is running and which restarts the service if not. As an example for apache and an interval of 10 minutes:
*/10 * * * * /usr/local/etc/rc.d/apache22 status >/dev/null 2>&1 || /usr/local/etc/rc.d/apache22 restart
For the use case of this service/machine, this is enough. In case of a problem with the service, a mail with the restart output would arrive each time it runs, else only after a reboot for which the service did not restart.
GD Star Rating
loading…
GD Star Rating
loading…
Today I had again some energy to look at why mono fails to build on FreeBSD–current.
I decided to do a debug-build of mono. This did not work initially, I had to produce some patches.
Does this mean nobody is doing debug builds of mono on FreeBSD?
I have to say, this experience with lang/mono is completely unsatisfying.
Ok, bottom line, either the debug build seems to prevent a race condition in most cases (I had a lot less lockups for each of the two builds I did).
Whatever it is, I do not care ATM (if the configure stuff is looking at the architecture of the system, it may be the case that the i386-portbld-freebsdX does not enable some important stuff which would be enabled when run with i486-portbld-freebsdX or better). Here are the patches I used in case someone is interested (warning, copy&paste converted tabs to spaces, you also have to apply the map.c (a generated file… maybe a touch of the right file would allow to apply this patch in the normal patch stage) related stuff when the build fails, else there is some parser error in mono):
--- mcs/class/Mono.Posix/Mono.Unix/UnixProcess.cs.orig 2010-01-29 11:34:00.592323482 +0100
+++ mcs/class/Mono.Posix/Mono.Unix/UnixProcess.cs 2010-01-29 11:34:18.540607357 +0100
@@ -57,7 +57,7 @@ namespace Mono.Unix {
int r = Native.Syscall.waitpid (pid, out status,
Native.WaitOptions.WNOHANG | Native.WaitOptions.WUNTRACED);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
- return r;
+ return status;
}
public int ExitCode {
--- mono/io-layer/processes.c.orig 2010-01-29 11:36:08.904331535 +0100
+++ mono/io-layer/processes.c 2010-01-29 11:42:21.819159544 +0100
@@ -160,7 +160,7 @@ static gboolean waitfor_pid (gpointer te
ret = waitpid (process->id, &status, WNOHANG);
} while (errno == EINTR);
- if (ret <= 0) {
+ if (ret == 0 || (ret < 0 && errno != ECHILD)) {
/* Process not ready for wait */
#ifdef DEBUG
g_message ("%s: Process %d not ready for waiting for: %s",
@@ -169,6 +169,17 @@ static gboolean waitfor_pid (gpointer te
return (FALSE);
}
+
+ if (ret < 0 && errno == ECHILD) {
+#ifdef DEBUG
+ g_message ("%s: Process %d does not exist (anymore)", __func__,
+ process->id);
+#endif
+ /* Faking the return status. I do not know if it is correct
+ * to assume a successful exit.
+ */
+ status = 0;
+ }
#ifdef DEBUG
g_message ("%s: Process %d finished", __func__, ret);
--- mono/metadata/mempool.c.orig 2010-01-29 11:58:16.871052861 +0100
+++ mono/metadata/mempool.c 2010-01-29 12:30:45.143367454 +0100
@@ -212,12 +212,14 @@ mono_backtrace (int size)
EnterCriticalSection (&mempool_tracing_lock);
g_print ("Allocating %d bytesn", size);
+#if defined(HAVE_BACKTRACE_SYMBOLS)
symbols = backtrace (array, BACKTRACE_DEPTH);
names = backtrace_symbols (array, symbols);
for (i = 1; i < symbols; ++i) {
g_print ("t%sn", names [i]);
}
free (names);
+#endif
LeaveCriticalSection (&mempool_tracing_lock);
}
--- mono/metadata/metadata.c.orig 2010-01-29 11:59:38.552316989 +0100
+++ mono/metadata/metadata.c 2010-01-29 12:00:43.957337476 +0100
@@ -3673,12 +3673,16 @@ mono_backtrace (int limit)
void *array[limit];
char **names;
int i;
+#if defined(HAVE_BACKTRACE_SYMBOLS)
backtrace (array, limit);
names = backtrace_symbols (array, limit);
for (i =0; i < limit; ++i) {
g_print ("t%sn", names [i]);
}
g_free (names);
+#else
+ g_print ("No backtrace available.n");
+#endif
}
#endif
--- support/map.c.orig 2010-01-29 12:05:22.374653708 +0100
+++ support/map.c 2010-01-29 12:10:29.024412452 +0100
@@ -216,7 +216,7 @@
#define _cnm_dump(to_t, from) do {} while (0)
#endif /* def _CNM_DUMP */
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(__FreeBSD__)
#define _cnm_return_val_if_overflow(to_t,from,val) G_STMT_START {
int uns = _cnm_integral_type_is_unsigned (to_t);
gint64 min = (gint64) _cnm_integral_type_min (to_t);
GD Star Rating
loading…
GD Star Rating
loading…
I try to build mono on FreeBSD–current (it is a dependency of some GNOME program). Unfortunately this does not work correctly.
What I see are hangs of the build. If I stop the build when it hangs and restart it, it will continue and succeed to process the build steps a little bit further, but then it hangs again.
If I ktrace the hanging process, I see that there is a call to wait returning with the error message that the child does not exist. Then there is a call to nanosleep.
It looks to me like this process missed some SIGCLD (or is waiting for something which did not exist at all), and a loop is waiting for a child to exit. This loop probably has no proper condition for the fact that there is no such child (anymore). As such it will stay forever in this loop.
So I grepped a litte bit around in mono and found the following code in <mono-src-dir>/mcs/class/Mono.Posix/Mono.Unix/UnixProcess.cs:
public void WaitForExit ()
{
int status;
int r;
do {
r = Native.Syscall.waitpid (pid, out status, (Native.WaitOptions) 0);
} while (UnixMarshal.ShouldRetrySyscall (r));
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
This does look a little bit as it could be related to the problem I see, but ShouldRetrySyscall only returns true if the errno is EINTR. So this looks correct.
I looked a little bit more at this file and it looks like either I do not understand the semantic of this language, or GetProcessStatus does return the returnvalue of the waitpid call instead of the status (which is not what it shall return to my understanding). If I am correct, it can not really detect the status of a process. It would be very bad if such a fundamental thing went unnoticed in mono… which does not put a good light on the unit-tests (if any) or the general testing of mono. For this reason I hope I am wrong.
I did not stop there, as this part does not look like it is the problem. I found the following in mono/io-layer/processes.c:
static gboolean waitfor_pid (gpointer test, gpointer user_data)
{
...
do {
ret = waitpid (process->id, &status, WNOHANG);
} while (errno == EINTR);
if (ret <= 0) {
/* Process not ready for wait */
#ifdef DEBUG
g_message ("%s: Process %d not ready for waiting for: %s",
__func__, process->id, g_strerror (errno));
#endif
return (FALSE);
}
#ifdef DEBUG
g_message ("%s: Process %d finished", __func__, ret);
#endif
process->waited = TRUE;
...
}
And here we have the problem, I think. I changed the (ret <= 0) to (ret == 0 || (ret < 0 && errno != ECHILD)). This will not really give the correct status, but at least it should not block anymore and I should be able to see the difference during the build.
And now after testing, I see a difference, but the problem is still there. The wait with ECHILD is gone in the loop, but there is still some loop with a semaphore operation:
62960 mono CALL clock_gettime(0xd,0xbf9feef8)
62960 mono RET clock_gettime 0
62960 mono CALL semop(0x20c0000,0xbf9feef6,0x1)
62960 mono RET semop 0
62960 mono CALL semop(0x20c0000,0xbf9feef6,0x1)
62960 mono RET semop 0
62960 mono CALL semop(0x20c0000,0xbf9feef6,0x1)
62960 mono RET semop 0
62960 mono CALL semop(0x20c0000,0xbf9feef6,0x1)
62960 mono RET semop 0
62960 mono CALL nanosleep(0xbf9fef84,0)
62960 mono RET nanosleep 0
62960 mono CALL clock_gettime(0xd,0xbf9feef8)
62960 mono RET clock_gettime 0
62960 mono CALL semop(0x20c0000,0xbf9feef6,0x1)
62960 mono RET semop 0
62960 mono CALL semop(0x20c0000,0xbf9feef6,0x1)
62960 mono RET semop 0
62960 mono CALL semop(0x20c0000,0xbf9feef6,0x1)
62960 mono RET semop 0
62960 mono CALL semop(0x20c0000,0xbf9feef6,0x1)
62960 mono RET semop 0
62960 mono CALL nanosleep(0xbf9fef84,0)
OK, there is more going on. I think someone with more knowledge about mono should have a look at this (do not only look at this semop thing, but also look why it loses a child).
GD Star Rating
loading…
GD Star Rating
loading…