Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
boak
Aug 17, 2010

im gay

Mustach posted:

Are you verifying that nsd != -1 before trying to print the address?

I wasn't, but tried it after you suggested it. Its definitely > 0


Vanadium posted:

cli_addrlen needs to be socklen_t, not int

I changed that but its still segfaulting.


roomforthetuna posted:

Worth doing but I don't think it could be the problem, since any value in the addr is valid enough to print. Is the segfault in the printf or in the accept (or even sooner?)? Have you checked that sd is a valid socket descriptor before calling accept?

on the printf() - if I comment it out theres no segfault and the program continues along its merry way.

any other ideas?

Adbot
ADBOT LOVES YOU

Hughlander
May 11, 2005

Ledneh posted:

Is there any quick test, besides reading the compiler documentation (which is proving inconclusive), to see if my compiler is performing return value optimization, named OR unnamed?

code:
#include <iostream>
 
struct C
{
  C() {}
  C(const C&) { std::cout << "A copy was made.\n"; }
};
 
C f()
{
  return C();
}
 
int main()
{
  std::cout << "Hello World!\n";
  C obj = f();
}
Is the output:

Hello World!
A copy was made.
A copy was made.

or

Hello World!
A copy was made.

or

Hello World!

boak
Aug 17, 2010

im gay
having more issues with my file transfer program. I have two functions used to send/receive a file over the socket

send: http://pastebin.com/7bfhSHDh
recv: http://pastebin.com/VetaKAh1

basically the client calls the send function, server calls recv function.

For small files (< 1kb) this works flawlessly. I've just started testing it on larger files (a ~300 kb file and a ~600 kb file). And now the server is receiving an incorrect file size.

If I print the size variable just before it gets converted to network byte order in the send function, and just after it gets converted back in the receive function, the numbers on the server side is vastly lower.

client output: sending 336914 bytes
server output: receiving 9234 bytes

At first I thought i'd just hosed up the data types somewhere but they both look fine to me. Why is it working for low size values but not for higher ones? It sounds screamingly obvious but I can't seem to work it out.

ToxicFrog
Apr 26, 2008


tripwire posted:

Thanks. I wasn't asking because I need to write some code using tuples, I was just curious because it seemed like there had to be a good reason for only making tuples up to eight long. I wonder, outside of D and C++0x, are there any c-like strongly-typed languages in which its easy to make a tuple which accepts variable numbers of arguments of varying type?

Scala and Haskell both support tuples of arbitrary arity (although Scala is only slightly C-like and Haskell is not at all):

code:
Prelude> :t (1,2,3)
(1,2,3) :: (Num t, Num t1, Num t2) => (t, t1, t2)

scala> (1,2,3)
res0: (Int, Int, Int) = (1,2,3)
Note that in both cases it's a language feature rather than a parameterized Tuple class.

boak posted:

At first I thought i'd just hosed up the data types somewhere but they both look fine to me. Why is it working for low size values but not for higher ones? It sounds screamingly obvious but I can't seem to work it out.

You have, in fact, hosed up the data types.

- your call to write assumes that unsigned int is always 4 bytes, which may not be the case. (You also have a non-harmful but completely unnecessary cast to char*.) I would say "use sizeof" but if you're running the client and server on different architectures you don't even know that unsigned int is the same size on both.

- You're using htons/ntohs to do your network <-> host byte order conversion. You might want to read the man pages for those, especially the bit right at the start that says they have the following signatures:

code:
uint16_t htons(uint16_t hostshort);
uint16_t ntohs(uint16_t netshort);
unsigned long is almost certainly more than 16 bits wide, so it's no surprise this doesn't work.

I suggest using uint32_t for your size type, and using htonl/ntohl (Network To Host Long/Host To Network Long) to manipulate it:

code:
uint32_t s_size;

...

s_size = htonl(s_size);
write(fd, &s_size, sizeof(s_size));
This gives you a bunch of advantages: you know s_size is the same size on both client and server, you don't actually need to know how large it is (thanks to sizeof), and your htonl/ntohl calls will work because you're using the right calls for your data type.

ToxicFrog fucked around with this message at 16:11 on Nov 5, 2010

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

boak posted:

on the printf() - if I comment it out theres no segfault and the program continues along its merry way.

any other ideas?
Split it up more for debugging purposes! Is the crash in inet_ntoa or in printf?
code:
printf("Client connected: %s\n", inet_ntoa(cli_addr.sin_addr));
becomes
code:
char *tmp=inet_ntoa(cli_addr.sin_addr);
printf("Client connected: ");
fflush(stdout); //fflush just to make sure you don't think the crash is somewhere it isn't
printf("%s",tmp); //used printf in case that was causing the crash, coulda used puts
fflush(stdout);
printf("\n");

boak
Aug 17, 2010

im gay

ToxicFrog posted:

You have, in fact, hosed up the data types.

- your call to write assumes that unsigned int is always 4 bytes, which may not be the case. (You also have a non-harmful but completely unnecessary cast to char*.) I would say "use sizeof" but if you're running the client and server on different architectures you don't even know that unsigned int is the same size on both.

- You're using htons/ntohs to do your network <-> host byte order conversion. You might want to read the man pages for those, especially the bit right at the start that says they have the following signatures:

code:
uint16_t htons(uint16_t hostshort);
uint16_t ntohs(uint16_t netshort);
unsigned long is almost certainly more than 16 bits wide, so it's no surprise this doesn't work.

I suggest using uint32_t for your size type, and using htonl/ntohl (Network To Host Long/Host To Network Long) to manipulate it:

code:
uint32_t s_size;

...

s_size = htonl(s_size);
write(fd, &s_size, sizeof(s_size));
This gives you a bunch of advantages: you know s_size is the same size on both client and server, you don't actually need to know how large it is (thanks to sizeof), and your htonl/ntohl calls will work because you're using the right calls for your data type.

Thanks for the advice. Reading the man pages for htons() etc help me work out what was going on. I should have been using htonl() and ntohl() for my current implementation.

As for different data types, makes sense. I'll change them over.

Thanks for the help.


roomforthetuna posted:

Split it up more for debugging purposes! Is the crash in inet_ntoa or in printf?
code:
printf("Client connected: %s\n", inet_ntoa(cli_addr.sin_addr));
becomes
code:
char *tmp=inet_ntoa(cli_addr.sin_addr);
printf("Client connected: ");
fflush(stdout); //fflush just to make sure you don't think the crash is somewhere it isn't
printf("%s",tmp); //used printf in case that was causing the crash, coulda used puts
fflush(stdout);
printf("\n");

now segfaulting on printf("%s",tmp);

raminasi
Jan 25, 2005

a last drink with no ice

tripwire posted:

Thanks. I wasn't asking because I need to write some code using tuples, I was just curious because it seemed like there had to be a good reason for only making tuples up to eight long. I wonder, outside of D and C++0x, are there any c-like strongly-typed languages in which its easy to make a tuple which accepts variable numbers of arguments of varying type?

.Net 4.0 has tuples, although I've never used them from C# and can't speak to their usefulness in that language (it looks like if you want more than eight elements in your tuple, you make the eighth one another tuple, et cetera).

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

boak posted:

now segfaulting on printf("%s",tmp);
Try
code:
puts(tmp);
in place of that line?
Try
code:
printf("%x",tmp);
to check if inet_ntoa is returning null or something?
Try running it under a debugger so you can look at the variables' states after if crashes? (gdb is pretty useful but not much fun interface-wise. Worth learning though if you're going to be command-line programming much.)

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Ledneh posted:

Is there any quick test, besides reading the compiler documentation (which is proving inconclusive), to see if my compiler is performing return value optimization, named OR unnamed?

Hughlander's proposal covers normal RVO. If you want to test for NRVO, I'd test a few cases like these:

code:
struct A { A() { printf("A\n"); } A(const A&) { printf("A(const A&)\n"); } ~A() { printf("~A()"); } }
A test0() { A a; return a; }
A test1(bool b) { if (b) { A a; return a; } else { return A(); } }
A test2(bool b) { if (b) { A a; return a; } else { A a; return a; } }
A test3(bool b) { A a1, a2; if (b) { return a1; } else { return a2; } } // no NRVO possible here
A test4(bool b) { A a1; if (b) { return a1; } else { A a2; return a2; } } // NRVO only for 'a2'
Note that the non-trivial destructor is important because (1) in most cases, the classes you care about RVO for will have them and (2) NRVO can in theory be more aggressive if there isn't a destructor causing liveness problems, although I don't know if anyone does this.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Cool, thanks for the RVO tips, all. :)

Another optimization question. Say I have a program that, for simplicity's sake, uses one string literal (say, "pants") but constructs that literal as a std::string over and over (and over and over :suicide: ) again in code. This happens because my predecessors hate me.

Is it likely to gain me anything in the real world if, instead of repeatedly constructing that same literal, I wrap it in a class that goes something like this contrived-as-hell pseudocode?

code:
std::map<size_t /*hash*/, const char*> literalMap;

size_t hash(const std::string& h) { /*blah*/ }

class String
{
public:
   String(const char* literal)
   {
      if (literalMap.find(hash(literal)) != literalMap.end())
         mStr = literalMap[hash(literal)];   
      else
      {
         mStr = new std::string(literal);
         literals[hash(literal)] = mStr;
      }    
   }

private:
   std::string* mStr;
};

// ...

// (pretend I overloaded all the needed operators)
String s = "pants";
String y = "pants"; // no std::string ctor call
String z = "pants"; // ditto
// etc
Or would I waste more time hashing and searching the map as opposed to just constructing the strings, generally?

I'm guessing this can't be determined in the general case, and depends entirely on how many literals we're using/how many string constructions we're doing, but I thought I'd throw it out there. (right now std::string construction is accounting for like 25% of our runtime according to our profiler, which seems like total dogshit)

Ciaphas fucked around with this message at 01:18 on Nov 6, 2010

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
If your profile says you're spending a quarter of your time building std::strings, then yes, I would guess that it's telling the truth; consider just making a const global std::string for each of your literals, assuming you can't just avoid needing a std::string for the literal in the first place.

A uniquing cache sometimes makes sense (for non-literals), but you should implement it with a real hashtable instead of this crazy map keyed on hashes.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Argh, thanks. Why didn't I think of using a hash table in the first place :arghfist::smith:

(For what it's worth, the full list of literals that get used over and over and etc changes for every run of the program, it depends on an input file.)

(edit- I just realized i may be using the wrong word when I say 'literal.' God damnit it's too late for me to be thinking.)

Ciaphas fucked around with this message at 01:58 on Nov 6, 2010

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
A remarkably specific server-programming question - I have a server that loads extra functionality from plugins. The base server code is pretty tight, full of plenty of user-data integrity checks and such. The plugins also should be, but there's probably going to be a lot of them and likely written in haste, so I don't want to be relying on them being bulletproof, and I don't want a bad function crashing the whole server. (It's basically a MMORPG server, so crashing out is not acceptable behaviour for it.)

Is there a decent way of doing this? I don't need plugins to be sealed in an indestructible sandbox, since it'll be my own code, I don't need to protect against maliciousness - I just want it to fail gracefully if I have a bad function. It's most likely that if they explode it'll be from something like trying to access a null pointer, or an unsigned array index accidentally going to 0xffffffff,

Is there a decent(ish) way to do this? Maybe something like trapping SIGSEGV and throwing an exception from there, and wrapping plugin function calls in a "try {function} catch (...)"?

(This is on a Linux system.)

Vanadium
Jan 8, 2005

Write the plugins in lua :)

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Vanadium posted:

Write the plugins in lua :)
That actually seemed like it might be a good idea, but from a quick glance it looks like I'd not have a lot of fun trying to make my way through complex 'struct' data inputs to the plugins nor calling back into virtual functions off a global pointer from inside a Lua script.

ToxicFrog
Apr 26, 2008


There are various tools (for both C and C++) that make that a lot less painless by automatically generating bindings. Unfortunately, I haven't used any of them, so the most I can tell you is that they exist and I hear people use them.

E: also, even if this is ugly, it's likely to be less ugly than manually signal fiddling and whatnot - which won't protect you if the plugin corrupts something in your server causing it to crash later, either.

ToxicFrog fucked around with this message at 03:33 on Nov 6, 2010

Fecotourist
Nov 1, 2008
Boost.python isn't lua, but it's really very well done. I've never used the embedded python functionality myself, but wrapping C++ for Python (the important part) is like magic.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


rjmccall posted:

If your profile says you're spending a quarter of your time building std::strings, then yes, I would guess that it's telling the truth; consider just making a const global std::string for each of your literals, assuming you can't just avoid needing a std::string for the literal in the first place.

A uniquing cache sometimes makes sense (for non-literals), but you should implement it with a real hashtable instead of this crazy map keyed on hashes.

What I ended up with before I left work
code:
typedef boost::unordered_map<std::string, const std::string*> StringMap;

class MyString
{
public:
   MyString(const std::string& s)
   {
      if (s in mStringMap)
         mStr = mStringMap[s];
      else
      {
         mStr = new std::string(s);
         // there's also some lowercasing bullshit in here JUST BECAUSE i don't even loving know
         mStringMap[s] = mStr;
      }
   }
   // other constructors and such
private:
   std::string* mStr;
   static StringMap mStringMap;
};
I wanted to post this because it made me realize that on Fridays, I am literally retarded :saddowns:

(did a drat good job for performance though... can't wait to get some sleep and look at this again in the morning when my brain is fixed and I can make it better)

Ciaphas fucked around with this message at 06:20 on Nov 6, 2010

shrughes
Oct 11, 2008

(call/cc call/cc)

ToxicFrog posted:

Scala and Haskell both support tuples of arbitrary arity (although Scala is only slightly C-like and Haskell is not at all):

code:
Prelude> :t (1,2,3)
(1,2,3) :: (Num t, Num t1, Num t2) => (t, t1, t2)

scala> (1,2,3)
res0: (Int, Int, Int) = (1,2,3)
Note that in both cases it's a language feature rather than a parameterized Tuple class.

code:
Prelude> (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1\
,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)

<interactive>:1:0:
    A 100-tuple is too large for GHC
      (max size is 62)
      Workaround: use nested tuples or define a data type
The Haskell 98 standard requires that implementations support tuples up to size 15.

Here's how GHC implements tuples: http://www.haskell.org/ghc/docs/6.12.2/html/libraries/ghc-prim-0.2.0.0/src/GHC-Tuple.html An excerpt:

GHC.Tuple posted:

data (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__
= (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__
data (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__
= (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__
{- Manuel says: Including one more declaration gives a segmentation fault.
data (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__ k__
= (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__ k__

shrughes
Oct 11, 2008

(call/cc call/cc)
Edit: er, I meant this post to be an edit.

It's impossible to be generic over tuples with respect to the size of a tuple. Each tuple type is completely independent.

Duke of Straylight
Oct 22, 2008

by Y Kant Ozma Post

roomforthetuna posted:

Is there a decent(ish) way to do this? Maybe something like trapping SIGSEGV and throwing an exception from there, and wrapping plugin function calls in a "try {function} catch (...)"?

Yeah, sigaction(2) (though you probably know more about how to use it than I do). Might have to be careful if you're combining multithreading with signals, and don't forget that SIGFPE, SIGILL, SIGSEGV and etc. are just a small part of the ways code could go wrong - you could still be hosed over by resource leaks, poor performance or nontermination, memory corruption... so if you do implement this level of protection, better not advertise it so people won't think they can depend on it.

Duke of Straylight fucked around with this message at 11:34 on Nov 6, 2010

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
You could go the way Chrome does it and encapsulate each plugin in its own process. That way there's no chance of a crashing plugin going and scribbling over some important data needed by the server itself.

Though you'll need to keep in mind that a crashing plugin could still be sending erroneous data to the core, but there's really no way to avoid that except for writing the plugins so they don't crash in the first place.

The alternative to full memory-space isolation is to use something "safe" like Lua, which will guarantee that even if the plugin fails, it won't wreck anything outside of its own state.

Hughlander
May 11, 2005

Ledneh posted:

Cool, thanks for the RVO tips, all. :)

Another optimization question. Say I have a program that, for simplicity's sake, uses one string literal (say, "pants") but constructs that literal as a std::string over and over (and over and over :suicide: ) again in code. This happens because my predecessors hate me.

Is it likely to gain me anything in the real world if, instead of repeatedly constructing that same literal, I wrap it in a class that goes something like this contrived-as-hell pseudocode?

code:
std::map<size_t /*hash*/, const char*> literalMap;

size_t hash(const std::string& h) { /*blah*/ }

class String
{
public:
   String(const char* literal)
   {
      if (literalMap.find(hash(literal)) != literalMap.end())
         mStr = literalMap[hash(literal)];   
      else
      {
         mStr = new std::string(literal);
         literals[hash(literal)] = mStr;
      }    
   }

private:
   std::string* mStr;
};

// ...

// (pretend I overloaded all the needed operators)
String s = "pants";
String y = "pants"; // no std::string ctor call
String z = "pants"; // ditto
// etc
Or would I waste more time hashing and searching the map as opposed to just constructing the strings, generally?

I'm guessing this can't be determined in the general case, and depends entirely on how many literals we're using/how many string constructions we're doing, but I thought I'd throw it out there. (right now std::string construction is accounting for like 25% of our runtime according to our profiler, which seems like total dogshit)

Speaking as someone who had this problems years ago (Though ours were worse because the function parameters were std::string, no const, no reference.) We got a hell of a lot of performance just analyzing the code paths and changing things to const char* and std::string&. Something else to consider depending on your requirements, though the hashmap should work as well.

Standish
May 21, 2001

Ledneh posted:

Another optimization question. Say I have a program that, for simplicity's sake, uses one string literal (say, "pants") but constructs that literal as a std::string over and over (and over and over :suicide: ) again in code. This happens because my predecessors hate me.

Is it likely to gain me anything in the real world if, instead of repeatedly constructing that same literal, I wrap it in a class that goes something like this contrived-as-hell pseudocode?
Yes, this is a fairly widespread pattern called string interning.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Duke of Straylight posted:

Yeah, sigaction(2) (though you probably know more about how to use it than I do). Might have to be careful if you're combining multithreading with signals, and don't forget that SIGFPE, SIGILL, SIGSEGV and etc. are just a small part of the ways code could go wrong - you could still be hosed over by resource leaks, poor performance or nontermination, memory corruption... so if you do implement this level of protection, better not advertise it so people won't think they can depend on it.
Right, as I said it's just for my own code, as a way to make dynamic changes a bit more robust. The chances of accidental wide-scale memory corruption are much much smaller than the chances of an accidental division by zero or bad pointer. I can't realistically do most of the other suggestions, since the plugin functions will be needing access to the global data, so all I'm really looking for is a "break out of the function instead of crashing" protection, not a full-scale most-robust-possible option. (While that would be nice, it would be so much more work to implement that way that it's not worth it.)

roomforthetuna fucked around with this message at 20:28 on Nov 6, 2010

tef
May 30, 2004

-> some l-system crap ->

shrughes posted:

Edit: er, I meant this post to be an edit.

It's impossible to be generic over tuples with respect to the size of a tuple. Each tuple type is completely independent.

What about dependent typed languges :3:

shrughes
Oct 11, 2008

(call/cc call/cc)

tef posted:

What about dependent typed languges :3:

I was talking about Haskell, specifically.

Besides, for different implementations of tuple types, it is possible to be generic, anyway.

ToxicFrog
Apr 26, 2008


shrughes posted:

Tuples in Haskell

Consider me enlightened (and somewhat disappointed).

I tried the same test in Scala. It chokes once it hits size 22. :(

Yeah, realistically a tuple with that many elements is a sign that you should be using an immutable list or a class instance or something, but still.

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender

shrughes posted:

I was talking about Haskell, specifically.

Besides, for different implementations of tuple types, it is possible to be generic, anyway.

Do you happen to know of any languages that do tuple-as-cons where (a,b,c) is just sugar for the type (a,(b,(c,())))?

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Standish posted:

Yes, this is a fairly widespread pattern called string interning.

Ah, I am enlightened! Thanks.

And thanks to everyone else for the ideas and suggestions, I've got more ammo for Monday now :)

(edit) A couple of related questions. One, I just saw boost::flyweight, and uh, would it do what I just did automagically? :saddowns:

Second, while reading about string interning I saw Copy-on-Write mentioned. Is that a compiler optimization, or is that something one has to code for?

Ciaphas fucked around with this message at 21:32 on Nov 6, 2010

Mr.Radar
Nov 5, 2005

You guys aren't going to believe this, but that guy is our games teacher.

Ledneh posted:

(edit) A couple of related questions. One, I just saw boost::flyweight, and uh, would it do what I just did automagically? :saddowns:
It looks like it's close, but it doesn't do exactly what you want. That looks like it mainly reduces memory use, but only after you construct the object you're assigning to the value. If your code is spending most of its time in the constructor then it doesn't look like it'll help.

quote:

Second, while reading about string interning I saw Copy-on-Write mentioned. Is that a compiler optimization, or is that something one has to code for?

In this context it's a "code for" optimization. It's useful in the case where you have a bunch of objects representing e.g. an array or list or something and the objects present an interface to mutate that data, but you don't actually mutate the data often. With copy-on-write instead of copying all the data when you copy the object you copy the pointer to that data instead. You put off copying that data until you absolutely have to, i.e. when someone tries to mutate it. If you make lots of copies but don't mutate your data often it can significantly reduce your memory consumption and the amount of copying you do.

Here's a small example:
code:
class Foo {
    std::vector<int> my_data;
public:
    Foo() : my_data() {}
    /* Copy constructor copies data. */
    Foo(const Foo& other) : my_data(other.begin(), other.end()) {}
    ~Foo() {}
    const std::vector<int> &get_data() { return my_data; }
    void append_value(int val) { my_data.push_back(val); }
};

class COW_Foo {
    std::shared_ptr<std::vector<int> > my_data;
public:
    Foo() : my_data(new std::vector<int>()) {}
    /* Copy constructor copies reference. */
    Foo(const Foo& other) : my_data(other.my_data) {}
    ~Foo() {}
    const std::vector<int>& get_data() { return *my_data; }
    /* Append copies data. */
    void append_value(int val) {
        if(my_data.use_count() > 1) { /* Optimization: only copy when data is shared;
                                         not thread-safe. For thread safety always copy
                                         or use a mutex. */
            my_data.reset(new std::vector<int>(my_data->begin(), my_data->end()));
        }
        my_data->push_back(val);
    }
};

Mr.Radar fucked around with this message at 01:41 on Nov 7, 2010

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
Just in case someone else was interested in the idea, it turns out that sigaction won't really help with recovering after a SIGSEGV - you can't throw an exception from inside the signal handler, nor do anything that will take you back to a relatively safe point in the code, except by crazy horrible direct stack pointer manipulation. So it seems I'm stuck with either "rewrite everything so I can use some sort of scripting language for the plugins" or "just write the dynamic plugin functions even more carefully".

Who'd have thought I'd wish for something like Microsoft's __try and __catch.

Duke of Straylight
Oct 22, 2008

by Y Kant Ozma Post
setjmp() and longjmp() maybe? Or sigsetjmp() and siglongjmp(), it appears that Wikipedia warns about using setjmp() and longjmp() together with signal handling.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Duke of Straylight posted:

setjmp() and longjmp() maybe? Or sigsetjmp() and siglongjmp(), it appears that Wikipedia warns about using setjmp() and longjmp() together with signal handling.
Thanks, sigsetjmp and siglongjmp seem to be almost doing what I was hoping for - it's fighting with libevent a bit, and seems to not actually restore the stack as the manpages claim, but I can get it to just about behave, and since it's something that ideally won't be going to come up anyway, the shakiness is acceptable.

pseudorandom name
May 6, 2007

What do you expect siglongjmp() to do to the stack that it isn't doing for you?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

pseudorandom name posted:

What do you expect siglongjmp() to do to the stack that it isn't doing for you?
I think I was hoping it would restore the stack length and contents, but it just rewinds the length, or something, such that this works okay:
code:
if (!sigsetjmp(bla,1)) {
 dodgyfunction();
} else {
 logerror();
}
But this doesn't work:
code:
bool preparefordodgyfunction() {
 doadditionalprep();
 return sigsetjmp(bla,1);
}

if (!preparefordodgyfunction()) {
 dodgyfunction();
 puts("Test1\n");
} else {
 logerror();
 puts("Test2\n");
}
puts("Test3\n");
In this latter case, after a signal does the siglongjmp it does resume inside preparefordodgyfunction as you'd expect, but where it returns from that function it comes out after dodgyfunction, not after preparefordodgyfunction.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
roomforthetuna, I was wondering what you were trying to scheme with that kind of recovery. I don't mean to attack what you're doing, but rather I'm curious since I'm scheming some stuff with plugins and c++ too. I'm a bit paranoid of a plugin blowing up everything. What I am planning to do is to run untrusted plugins in a seperate process space. But the idea there is eventually one would get cozy with them and let the main process load them up to reduce overhead of copying stuff back and forth. The only (and big) downside is even after trusting the plugin, it could very well go out of its way to blow everything up.

raminasi
Jan 25, 2005

a last drink with no ice

roomforthetuna posted:

I think I was hoping it would restore the stack length and contents, but it just rewinds the length, or something, such that this works okay:
code:
if (!sigsetjmp(bla,1)) {
 dodgyfunction();
} else {
 logerror();
}
But this doesn't work:
code:
bool preparefordodgyfunction() {
 doadditionalprep();
 return sigsetjmp(bla,1);
}

if (!preparefordodgyfunction()) {
 dodgyfunction();
 puts("Test1\n");
} else {
 logerror();
 puts("Test2\n");
}
puts("Test3\n");
In this latter case, after a signal does the siglongjmp it does resume inside preparefordodgyfunction as you'd expect, but where it returns from that function it comes out after dodgyfunction, not after preparefordodgyfunction.

All the man pages I'm finding say that you can't return from a function that calls setjmp (or sigsetjmp) and expect a corresponding longjmp to work correctly.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Yep, that's one of the major restrictions on setjmp. The other is that, if you modify a non-volatile local variable after a setjmp, it will have indeterminate state after a longjmp.

Basically, setjmp is specifically designed to allow the implementation to only capture register state.

Adbot
ADBOT LOVES YOU

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Rocko Bonaparte posted:

roomforthetuna, I was wondering what you were trying to scheme with that kind of recovery. I don't mean to attack what you're doing, but rather I'm curious since I'm scheming some stuff with plugins and c++ too. I'm a bit paranoid of a plugin blowing up everything. What I am planning to do is to run untrusted plugins in a seperate process space. But the idea there is eventually one would get cozy with them and let the main process load them up to reduce overhead of copying stuff back and forth. The only (and big) downside is even after trusting the plugin, it could very well go out of its way to blow everything up.
What I'm doing is a MMORPG of mini-games (kind of along the lines of Puzzle Pirates). The only thing the mini-games really do with the server is report results, but then the server needs to know how to parse the results, and how to use them to update scores and give game-money rewards. Since all the code is by me, I don't need to worry about plugins going out of their way to blow stuff up, I only need to be concerned about accidental things. I probably could do this by running it in a separate process and making a much more complex series of inquiries to that process, but the extra complexity involved in doing that (that I'd have to work around for each subsequent mini-game I add) would probably not be worth it.

These things are plugins because they're likely to update a lot more frequently than the core server (both for changes to game scoring and for new games being added), and as dynamically loaded plugins I can even switch them out while the server is still running, thus sparing the "hey everyone, you're all going to get disconnected for an update!" messages common in many MMORPGs. But because they'll be frequently changed and easily switched out, there's a very good chance I'll also screw something up occasionally, hence the wish for a "don't crash out and disconnect everyone" solution.

quote:

All the man pages I'm finding say that you can't return from a function that calls setjmp (or sigsetjmp) and expect a corresponding longjmp to work correctly.
My bad, I must've just missed that. Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply