X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdbusnameowning.c;h=d39faea32b09393329930693dca9b73d7a8005ba;hb=472e727299d0525c82b6df97d557d2bf8cf915de;hp=576d14453d0acf3414813f8e11305c1e108cf5e6;hpb=45e604d029980f90a7304b6311fc43cc0cc2ab69;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdbusnameowning.c b/gio/gdbusnameowning.c index 576d144..d39faea 100644 --- a/gio/gdbusnameowning.c +++ b/gio/gdbusnameowning.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: David Zeuthen */ @@ -30,8 +28,11 @@ #include "gdbusprivate.h" #include "gdbusconnection.h" +#ifdef G_OS_UNIX +#include "gkdbusconnection.h" +#endif + #include "glibintl.h" -#include "gioalias.h" /** * SECTION:gdbusnameowning @@ -41,7 +42,8 @@ * * Convenience API for owning bus names. * - * Simple application owning a nameFIXME: MISSING XINCLUDE CONTENT + * A simple example for owning a name can be found in + * [gdbus-example-own-name.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-own-name.c) */ G_LOCK_DEFINE_STATIC (lock); @@ -75,7 +77,7 @@ typedef struct guint name_acquired_subscription_id; guint name_lost_subscription_id; - gboolean cancelled; + volatile gboolean cancelled; /* must hold lock when reading or modifying */ gboolean needs_release; } Client; @@ -106,8 +108,7 @@ client_unref (Client *client) g_dbus_connection_signal_unsubscribe (client->connection, client->name_lost_subscription_id); g_object_unref (client->connection); } - if (client->main_context != NULL) - g_main_context_unref (client->main_context); + g_main_context_unref (client->main_context); g_free (client->name); if (client->user_data_free_func != NULL) client->user_data_free_func (client->user_data); @@ -200,6 +201,7 @@ schedule_call_in_idle (Client *client, CallType call_type) call_in_idle_cb, data, (GDestroyNotify) call_handler_data_free); + g_source_set_name (idle_source, "[gio] call_in_idle_cb"); g_source_attach (idle_source, client->main_context); g_source_unref (idle_source); } @@ -207,37 +209,53 @@ schedule_call_in_idle (Client *client, CallType call_type) static void do_call (Client *client, CallType call_type) { + GMainContext *current_context; + /* only schedule in idle if we're not in the right thread */ - if (g_main_context_get_thread_default () != client->main_context) + current_context = g_main_context_ref_thread_default (); + if (current_context != client->main_context) schedule_call_in_idle (client, call_type); else actually_do_call (client, client->connection, call_type); + g_main_context_unref (current_context); } static void call_acquired_handler (Client *client) { + G_LOCK (lock); if (client->previous_call != PREVIOUS_CALL_ACQUIRED) { client->previous_call = PREVIOUS_CALL_ACQUIRED; if (!client->cancelled) { + G_UNLOCK (lock); do_call (client, CALL_TYPE_NAME_ACQUIRED); + goto out; } } + G_UNLOCK (lock); + out: + ; } static void call_lost_handler (Client *client) { + G_LOCK (lock); if (client->previous_call != PREVIOUS_CALL_LOST) { client->previous_call = PREVIOUS_CALL_LOST; if (!client->cancelled) { + G_UNLOCK (lock); do_call (client, CALL_TYPE_NAME_LOST); + goto out; } } + G_UNLOCK (lock); + out: + ; } /* ---------------------------------------------------------------------------------------------------- */ @@ -282,27 +300,11 @@ on_name_lost_or_acquired (GDBusConnection *connection, /* ---------------------------------------------------------------------------------------------------- */ static void -request_name_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +process_request_name_reply (Client *client, + guint32 request_name_reply) { - Client *client = user_data; - GVariant *result; - guint32 request_name_reply; gboolean subscribe; - request_name_reply = 0; - result = NULL; - - result = g_dbus_connection_call_finish (client->connection, - res, - NULL); - if (result != NULL) - { - g_variant_get (result, "(u)", &request_name_reply); - g_variant_unref (result); - } - subscribe = FALSE; switch (request_name_reply) @@ -330,30 +332,75 @@ request_name_cb (GObject *source_object, break; } + if (subscribe) { + GDBusConnection *connection = NULL; + + /* if cancelled, there is no point in subscribing to signals - if not, make sure + * we use a known good Connection object since it may be set to NULL at any point + * after being cancelled + */ + G_LOCK (lock); + if (!client->cancelled) + connection = g_object_ref (client->connection); + G_UNLOCK (lock); + /* start listening to NameLost and NameAcquired messages */ - client->name_lost_subscription_id = - g_dbus_connection_signal_subscribe (client->connection, - "org.freedesktop.DBus", - "org.freedesktop.DBus", - "NameLost", - "/org/freedesktop/DBus", - client->name, - on_name_lost_or_acquired, - client, - NULL); - client->name_acquired_subscription_id = - g_dbus_connection_signal_subscribe (client->connection, - "org.freedesktop.DBus", - "org.freedesktop.DBus", - "NameAcquired", - "/org/freedesktop/DBus", - client->name, - on_name_lost_or_acquired, - client, - NULL); + if (connection != NULL) + { + client->name_lost_subscription_id = + g_dbus_connection_signal_subscribe (connection, + "org.freedesktop.DBus", + "org.freedesktop.DBus", + "NameLost", + "/org/freedesktop/DBus", + client->name, + G_DBUS_SIGNAL_FLAGS_NONE, + on_name_lost_or_acquired, + client, + NULL); + client->name_acquired_subscription_id = + g_dbus_connection_signal_subscribe (connection, + "org.freedesktop.DBus", + "org.freedesktop.DBus", + "NameAcquired", + "/org/freedesktop/DBus", + client->name, + G_DBUS_SIGNAL_FLAGS_NONE, + on_name_lost_or_acquired, + client, + NULL); + g_object_unref (connection); + } } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +request_name_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + Client *client = user_data; + GVariant *result; + guint32 request_name_reply; + + request_name_reply = 0; + result = NULL; + + /* don't use client->connection - it may be NULL already */ + result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + NULL); + if (result != NULL) + { + g_variant_get (result, "(u)", &request_name_reply); + g_variant_unref (result); + } + + process_request_name_reply (client, request_name_reply); client_unref (client); } @@ -395,20 +442,41 @@ has_connection (Client *client) client); /* attempt to acquire the name */ - g_dbus_connection_call (client->connection, - "org.freedesktop.DBus", /* bus name */ - "/org/freedesktop/DBus", /* object path */ - "org.freedesktop.DBus", /* interface name */ - "RequestName", /* method name */ - g_variant_new ("(su)", - client->name, - client->flags), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback) request_name_cb, - client_ref (client)); + if (G_IS_KDBUS_CONNECTION (g_dbus_connection_get_stream (client->connection))) + { + GVariant *result; + guint32 request_name_reply; + + request_name_reply = 0; + result = NULL; + + result = _g_kdbus_RequestName (client->connection, client->name, client->flags, NULL); + + if (result != NULL) + { + g_variant_get (result, "(u)", &request_name_reply); + g_variant_unref (result); + } + + process_request_name_reply (client, request_name_reply); + } + else + { + g_dbus_connection_call (client->connection, + "org.freedesktop.DBus", /* bus name */ + "/org/freedesktop/DBus", /* object path */ + "org.freedesktop.DBus", /* interface name */ + "RequestName", /* method name */ + g_variant_new ("(su)", + client->name, + client->flags), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) request_name_cb, + client_ref (client)); + } } @@ -419,6 +487,15 @@ connection_get_cb (GObject *source_object, { Client *client = user_data; + /* must not do anything if already cancelled */ + G_LOCK (lock); + if (client->cancelled) + { + G_UNLOCK (lock); + goto out; + } + G_UNLOCK (lock); + client->connection = g_bus_get_finish (res, NULL); if (client->connection == NULL) { @@ -450,19 +527,19 @@ connection_get_cb (GObject *source_object, /** * g_bus_own_name_on_connection: - * @connection: A #GDBusConnection that is not closed. - * @name: The well-known name to own. - * @flags: A set of flags from the #GBusNameOwnerFlags enumeration. - * @name_acquired_handler: Handler to invoke when @name is acquired or %NULL. - * @name_lost_handler: Handler to invoke when @name is lost or %NULL. - * @user_data: User data to pass to handlers. - * @user_data_free_func: Function for freeing @user_data or %NULL. + * @connection: a #GDBusConnection + * @name: the well-known name to own + * @flags: a set of flags from the #GBusNameOwnerFlags enumeration + * @name_acquired_handler: (allow-none): handler to invoke when @name is acquired or %NULL + * @name_lost_handler: (allow-none): handler to invoke when @name is lost or %NULL + * @user_data: user data to pass to handlers + * @user_data_free_func: (allow-none): function for freeing @user_data or %NULL * * Like g_bus_own_name() but takes a #GDBusConnection instead of a * #GBusType. * - * Returns: An identifier (never 0) that an be used with - * g_bus_unown_name() to stop owning the name. + * Returns: an identifier (never 0) that an be used with + * g_bus_unown_name() to stop owning the name * * Since: 2.26 */ @@ -478,7 +555,6 @@ g_bus_own_name_on_connection (GDBusConnection *connection, Client *client; g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0); - g_return_val_if_fail (!g_dbus_connection_is_closed (connection), 0); g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0); G_LOCK (lock); @@ -492,9 +568,7 @@ g_bus_own_name_on_connection (GDBusConnection *connection, client->name_lost_handler = name_lost_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; - client->main_context = g_main_context_get_thread_default (); - if (client->main_context != NULL) - g_main_context_ref (client->main_context); + client->main_context = g_main_context_ref_thread_default (); client->connection = g_object_ref (connection); @@ -515,44 +589,43 @@ g_bus_own_name_on_connection (GDBusConnection *connection, /** * g_bus_own_name: - * @bus_type: The type of bus to own a name on. - * @name: The well-known name to own. - * @flags: A set of flags from the #GBusNameOwnerFlags enumeration. - * @bus_acquired_handler: Handler to invoke when connected to the bus of type @bus_type or %NULL. - * @name_acquired_handler: Handler to invoke when @name is acquired or %NULL. - * @name_lost_handler: Handler to invoke when @name is lost or %NULL. - * @user_data: User data to pass to handlers. - * @user_data_free_func: Function for freeing @user_data or %NULL. + * @bus_type: the type of bus to own a name on + * @name: the well-known name to own + * @flags: a set of flags from the #GBusNameOwnerFlags enumeration + * @bus_acquired_handler: (allow-none): handler to invoke when connected to the bus of type @bus_type or %NULL + * @name_acquired_handler: (allow-none): handler to invoke when @name is acquired or %NULL + * @name_lost_handler: (allow-none): handler to invoke when @name is lost or %NULL + * @user_data: user data to pass to handlers + * @user_data_free_func: (allow-none): function for freeing @user_data or %NULL * * Starts acquiring @name on the bus specified by @bus_type and calls * @name_acquired_handler and @name_lost_handler when the name is - * acquired respectively lost. Callbacks will be invoked in the thread-default main - * loop of the thread you are calling this function from. + * acquired respectively lost. Callbacks will be invoked in the + * [thread-default main context][g-main-context-push-thread-default] + * of the thread you are calling this function from. * * You are guaranteed that one of the @name_acquired_handler and @name_lost_handler * callbacks will be invoked after calling this function - there are three * possible cases: - * - * - * @name_lost_handler with a %NULL connection (if a connection to the bus can't be made). - * - * - * @bus_acquired_handler then @name_lost_handler (if the name can't be obtained) - * - * - * @bus_acquired_handler then @name_acquired_handler (if the name was obtained). - * - * + * + * - @name_lost_handler with a %NULL connection (if a connection to the bus + * can't be made). + * + * - @bus_acquired_handler then @name_lost_handler (if the name can't be + * obtained) + * + * - @bus_acquired_handler then @name_acquired_handler (if the name was + * obtained). + * * When you are done owning the name, just call g_bus_unown_name() * with the owner id this function returns. * * If the name is acquired or lost (for example another application * could acquire the name if you allow replacement or the application - * currently owning the name exits), the handlers are also invoked. If the - * #GDBusConnection that is used for attempting to own the name - * closes, then @name_lost_handler is invoked since it is no - * longer possible for other processes to access the process. + * currently owning the name exits), the handlers are also invoked. + * If the #GDBusConnection that is used for attempting to own the name + * closes, then @name_lost_handler is invoked since it is no longer + * possible for other processes to access the process. * * You cannot use g_bus_own_name() several times for the same name (unless * interleaved with calls to g_bus_unown_name()) - only the first call @@ -571,12 +644,12 @@ g_bus_own_name_on_connection (GDBusConnection *connection, * before @name is requested from the bus. * * This behavior makes it very simple to write applications that wants - * to own names and export objects, see . + * to [own names][gdbus-owning-names] and export objects. * Simply register objects to be exported in @bus_acquired_handler and * unregister the objects (if any) in @name_lost_handler. * - * Returns: An identifier (never 0) that an be used with - * g_bus_unown_name() to stop owning the name. + * Returns: an identifier (never 0) that an be used with + * g_bus_unown_name() to stop owning the name. * * Since: 2.26 */ @@ -606,9 +679,7 @@ g_bus_own_name (GBusType bus_type, client->name_lost_handler = name_lost_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; - client->main_context = g_main_context_get_thread_default (); - if (client->main_context != NULL) - g_main_context_ref (client->main_context); + client->main_context = g_main_context_ref_thread_default (); if (map_id_to_client == NULL) { @@ -634,13 +705,49 @@ typedef struct { GClosure *name_lost_closure; } OwnNameData; +static OwnNameData * +own_name_data_new (GClosure *bus_acquired_closure, + GClosure *name_acquired_closure, + GClosure *name_lost_closure) +{ + OwnNameData *data; + + data = g_new0 (OwnNameData, 1); + + if (bus_acquired_closure != NULL) + { + data->bus_acquired_closure = g_closure_ref (bus_acquired_closure); + g_closure_sink (bus_acquired_closure); + if (G_CLOSURE_NEEDS_MARSHAL (bus_acquired_closure)) + g_closure_set_marshal (bus_acquired_closure, g_cclosure_marshal_generic); + } + + if (name_acquired_closure != NULL) + { + data->name_acquired_closure = g_closure_ref (name_acquired_closure); + g_closure_sink (name_acquired_closure); + if (G_CLOSURE_NEEDS_MARSHAL (name_acquired_closure)) + g_closure_set_marshal (name_acquired_closure, g_cclosure_marshal_generic); + } + + if (name_lost_closure != NULL) + { + data->name_lost_closure = g_closure_ref (name_lost_closure); + g_closure_sink (name_lost_closure); + if (G_CLOSURE_NEEDS_MARSHAL (name_lost_closure)) + g_closure_set_marshal (name_lost_closure, g_cclosure_marshal_generic); + } + + return data; +} + static void own_with_closures_on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { OwnNameData *data = user_data; - GValue params[2] = { { 0, }, { 0, } }; + GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION); g_value_set_object (¶ms[0], connection); @@ -649,6 +756,9 @@ own_with_closures_on_bus_acquired (GDBusConnection *connection, g_value_set_string (¶ms[1], name); g_closure_invoke (data->bus_acquired_closure, NULL, 2, params, NULL); + + g_value_unset (params + 0); + g_value_unset (params + 1); } static void @@ -657,7 +767,7 @@ own_with_closures_on_name_acquired (GDBusConnection *connection, gpointer user_data) { OwnNameData *data = user_data; - GValue params[2] = { { 0, }, { 0, } }; + GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION); g_value_set_object (¶ms[0], connection); @@ -666,6 +776,9 @@ own_with_closures_on_name_acquired (GDBusConnection *connection, g_value_set_string (¶ms[1], name); g_closure_invoke (data->name_acquired_closure, NULL, 2, params, NULL); + + g_value_unset (params + 0); + g_value_unset (params + 1); } static void @@ -674,7 +787,7 @@ own_with_closures_on_name_lost (GDBusConnection *connection, gpointer user_data) { OwnNameData *data = user_data; - GValue params[2] = { { 0, }, { 0, } }; + GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION); g_value_set_object (¶ms[0], connection); @@ -683,6 +796,9 @@ own_with_closures_on_name_lost (GDBusConnection *connection, g_value_set_string (¶ms[1], name); g_closure_invoke (data->name_lost_closure, NULL, 2, params, NULL); + + g_value_unset (params + 0); + g_value_unset (params + 1); } static void @@ -704,106 +820,87 @@ bus_own_name_free_func (gpointer user_data) /** * g_bus_own_name_with_closures: - * @bus_type: The type of bus to own a name on. - * @name: The well-known name to own. - * @flags: A set of flags from the #GBusNameOwnerFlags enumeration. + * @bus_type: the type of bus to own a name on + * @name: the well-known name to own + * @flags: a set of flags from the #GBusNameOwnerFlags enumeration * @bus_acquired_closure: (allow-none): #GClosure to invoke when connected to - * the bus of type @bus_type or %NULL. + * the bus of type @bus_type or %NULL * @name_acquired_closure: (allow-none): #GClosure to invoke when @name is - * acquired or %NULL. + * acquired or %NULL * @name_lost_closure: (allow-none): #GClosure to invoke when @name is lost or - * %NULL. + * %NULL * * Version of g_bus_own_name() using closures instead of callbacks for * easier binding in other languages. * - * Returns: An identifier (never 0) that an be used with - * g_bus_unown_name() to stop owning the name. + * Returns: an identifier (never 0) that an be used with + * g_bus_unown_name() to stop owning the name. * * Rename to: g_bus_own_name * * Since: 2.26 */ guint -g_bus_own_name_with_closures (GBusType bus_type, - const gchar *name, - GBusNameOwnerFlags flags, - GClosure *bus_acquired_closure, - GClosure *name_acquired_closure, - GClosure *name_lost_closure) +g_bus_own_name_with_closures (GBusType bus_type, + const gchar *name, + GBusNameOwnerFlags flags, + GClosure *bus_acquired_closure, + GClosure *name_acquired_closure, + GClosure *name_lost_closure) { - OwnNameData *data; - - data = g_new0 (OwnNameData, 1); - - if (bus_acquired_closure != NULL) - data->bus_acquired_closure = g_closure_ref (bus_acquired_closure); - - if (name_acquired_closure != NULL) - data->name_acquired_closure = g_closure_ref (name_acquired_closure); - - if (name_lost_closure != NULL) - data->name_lost_closure = g_closure_ref (name_lost_closure); - return g_bus_own_name (bus_type, name, flags, bus_acquired_closure != NULL ? own_with_closures_on_bus_acquired : NULL, name_acquired_closure != NULL ? own_with_closures_on_name_acquired : NULL, name_lost_closure != NULL ? own_with_closures_on_name_lost : NULL, - data, + own_name_data_new (bus_acquired_closure, + name_acquired_closure, + name_lost_closure), bus_own_name_free_func); } /** * g_bus_own_name_on_connection_with_closures: - * @connection: A #GDBusConnection that is not closed. - * @name: The well-known name to own. - * @flags: A set of flags from the #GBusNameOwnerFlags enumeration. + * @connection: a #GDBusConnection + * @name: the well-known name to own + * @flags: a set of flags from the #GBusNameOwnerFlags enumeration * @name_acquired_closure: (allow-none): #GClosure to invoke when @name is - * acquired or %NULL. - * @name_lost_closure: (allow-none): #GClosure to invoke when @name is lost or - * %NULL. + * acquired or %NULL + * @name_lost_closure: (allow-none): #GClosure to invoke when @name is lost + * or %NULL * - * Version of g_bus_own_name_on_connection() using closures instead of callbacks for - * easier binding in other languages. + * Version of g_bus_own_name_on_connection() using closures instead of + * callbacks for easier binding in other languages. * - * Returns: An identifier (never 0) that an be used with - * g_bus_unown_name() to stop owning the name. + * Returns: an identifier (never 0) that an be used with + * g_bus_unown_name() to stop owning the name. * * Rename to: g_bus_own_name_on_connection * * Since: 2.26 */ guint -g_bus_own_name_on_connection_with_closures (GDBusConnection *connection, - const gchar *name, - GBusNameOwnerFlags flags, - GClosure *name_acquired_closure, - GClosure *name_lost_closure) +g_bus_own_name_on_connection_with_closures (GDBusConnection *connection, + const gchar *name, + GBusNameOwnerFlags flags, + GClosure *name_acquired_closure, + GClosure *name_lost_closure) { - OwnNameData *data; - - data = g_new0 (OwnNameData, 1); - - if (name_acquired_closure != NULL) - data->name_acquired_closure = g_closure_ref (name_acquired_closure); - - if (name_lost_closure != NULL) - data->name_lost_closure = g_closure_ref (name_lost_closure); - return g_bus_own_name_on_connection (connection, name, flags, name_acquired_closure != NULL ? own_with_closures_on_name_acquired : NULL, name_lost_closure != NULL ? own_with_closures_on_name_lost : NULL, - data, + own_name_data_new (NULL, + name_acquired_closure, + name_lost_closure), bus_own_name_free_func); } /** * g_bus_unown_name: - * @owner_id: An identifier obtained from g_bus_own_name() + * @owner_id: an identifier obtained from g_bus_own_name() * * Stops owning a name. * @@ -836,7 +933,9 @@ g_bus_unown_name (guint owner_id) if (client != NULL) { /* Release the name if needed */ - if (client->needs_release && client->connection != NULL) + if (client->needs_release && + client->connection != NULL && + !g_dbus_connection_is_closed (client->connection)) { GVariant *result; GError *error; @@ -849,17 +948,20 @@ g_bus_unown_name (guint owner_id) * I believe this is a bug in the bus daemon. */ error = NULL; - result = g_dbus_connection_call_sync (client->connection, - "org.freedesktop.DBus", /* bus name */ - "/org/freedesktop/DBus", /* object path */ - "org.freedesktop.DBus", /* interface name */ - "ReleaseName", /* method name */ - g_variant_new ("(s)", client->name), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); + if (G_IS_KDBUS_CONNECTION (g_dbus_connection_get_stream (client->connection))) + result = _g_kdbus_ReleaseName (client->connection, client->name, &error); + else + result = g_dbus_connection_call_sync (client->connection, + "org.freedesktop.DBus", /* bus name */ + "/org/freedesktop/DBus", /* object path */ + "org.freedesktop.DBus", /* interface name */ + "ReleaseName", /* method name */ + g_variant_new ("(s)", client->name), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); if (result == NULL) { g_warning ("Error releasing name %s: %s", client->name, error->message); @@ -894,6 +996,3 @@ g_bus_unown_name (guint owner_id) client_unref (client); } } - -#define __G_DBUS_NAME_OWNING_C__ -#include "gioaliasdef.c"